Qt : pass values from a window to another - c++

I have a Qt App running two windows, a login window and a data window. I need to be able to pass a couple of values from the first to the second, but i can't figure out a way to do it, since - on my main.cpp file - i have :
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
LoginWindow loginWindow;
loginWindow.show();
return a.exec();
}
What i'd want would be :
LoginWindow loginWindow;
loginWindow.who();
// wait for user to input data in LoginWindow.......
// fetch datas from loginWindow
SecondWindow secondWindow;
secondWindow.show();
So, as soon as my LoginWindow is closed (after the login), the whole app is terminated. Plus, i can't extract datas drom LoginWindow to the main function, since i don't know when they'll be available.
How can i make this work ?
Thanks.

I would declare a local variable in Main() and pass it by-reference to the login window's constructor, i.e.:
string username;
LoginWindow loginwindow(username);
loginwindow.show();
Where the constructor is declared like this:
LoginWindow::LoginWindow(string& username);
Then LoginWindow can modify the string however it needs to, and when the call to show() returns, the user name will be stored in the local variable username. You can then pass that to the constructor of secondWindow in the same way.

That's a proper place for Qt's signals and slots. The simplest way to get going - just add one signal to LoginWindow class and one slot to DataWindow class:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
LoginWindow loginWindow;
DataWindow dataWindow;
QObject::connect(&loginWindow, SIGNAL(loginAcquired(LoginData)),
&dataWindow, SLOT(getLoginData(LoginData)));
QObject::connect(&loginWindow, SIGNAL(loginAcquired(LoginData)),
&dataWindow, SLOT(show()));
loginWindow.show();
return a.exec();
}

Related

Qt - Non Modal Dialog before Main Window is created

I've been struggling to do this : I want to show on a window a QWidget, or a QDialog before the MainWindow is created, but I cannot use exec() because it will enter its loop and won't create my MainWindow before I accept or reject the dialog.
The reason I want to do this is to have a widget showing information while the MainWindow constructs itself. I don't want to keep this extra window once the MainWindow is showing up.
I believe the issue comes from the fact that the main window is already created when a.exec() is called and the window won't show up before a.exec(). The solution I found is to use a QDialog instead and call exec() but it blocks the rest of the code which I don't want to happen.
Code :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start; //this is my custom QDialog, can be a QWidget if necessary.
qDebug() << "starting up!";
MainWindow w;
start.exec(); //I tried show() but it won't show up.
w.startApp(&start); //this function will do some stuff.
w.show();
//I don't want start to stay after mainwindow shows up
return a.exec();
}
Here is what I tried so far :
I tried to create and show the StartUpDialog while constructing the MainWindow but it won't work out.
Use start.show(), but it won't show before the mainwindow does, both for a QWidget and a QDialog.
Use start.exec(), this does what I want but it's modal and I couldn't make it non-modal with SetModal(false) or setWindowModality(Qt:NonModal).
I also tried to use start.exec() and attempted to reimplement accepted() and exec() so that it automatically calls accepted() as soon as it appears but it will still close the window.
Hopefully you can help me in that issue, and thanks for reading !
UPDATE : Solved thanks to Trap, here is how I made it :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start;
QSplashScreen *splash = new QSplashScreen();
StartUpWidget *start = new StartUpWidget(splash);
splash->resize(350,380);
start->show();
splash->raise();
splash->show();
qDebug() << "starting up!";
MainWindow w;
w.startApp(start);
w.show();
splash->finish(&w);
start->deleteLater();
splash->deleteLater();
return a.exec();
}
My only concern is that I use a Gif inside my widget using QMovie and updating it has to be done manually apparently.
If I understand your problem correctly (showing a dialog until your main window is created), you should have a look at the QSplashScreen class : http://doc.qt.io/qt-5/qsplashscreen.html

QMainWindow doesn't .show() but .showFullScreen() works

I have a desktop application that I'm building which checks a QSetting value and if it isn't set shows one QMainWindow class but if it is, shows a different QMainWindow class. The two classes are literally identical at this point as it's early on and don't really contain anything.
In my main function this is what I've got:
int main (int argc, char *argv[]) {
...
if (userToken == "NO_USER") {
LoginWindow w;
w.show();
} else {
MainWindow w;
w.show();
}
return a.exec();
}
The only difference in this between the default project set up from when I created the project is the addition of the conditional window load. Both MainWindow and LoginWindow don't have anything loading other than the ui file associated with them, they're functionally the same.
The weirdness is if I do w.showFullScreen() for the LoginWindow it will show up and take up the whole screen, if I do w.show() nothing at all happens, no compiler warnings|errors, application runs fine, just no window displays.
If I remove the conditional statements and LoginWindow references, MainWindow shows up fine.
Any idea why a call to .showFullScreen() would work but a call to .show() on the same class wouldn't?
I am not sure if this solves you problem, but there definitely is a bug in your code. You are instanciating the window objects on the stack inside a a tight scope, and as you know those objects will be destructed as soon as they go out of that scope. What you are doing is letting them go out of scope before the application is ever started.
Please try this instead:
int main (int argc, char *argv[]) {
...
if (userToken == "NO_USER") {
LoginWindow w;
w.show();
return a.exec();
} else {
MainWindow w;
w.show();
return a.exec();
}
}

Qt 5.3 Signals and Slots, Simple Function and Lambda Expression

I tried to Write a program using Qt 5.3 and I try to using signals and slots as practice. I wrote the following code (part of the code) :
void exitToWin()
{
exit(0);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QMessageBox EndBox;
QObject::connect((EndBox.button(QMessageBox::Ok)),SIGNAL(clicked()),exitToWin);
w.show();
EndBox.show();
return a.exec();
}
I even change the declaration of the function to static and I checked the expression with parentheses and without them while I am writing the connect command. but although what Qt documented and what its IDE guided to. also I read here and I tested it.
Moreover I tried with lambda expression as below:
QObject::connect((EndBox.button(QMessageBox::Ok)),SIGNAL(clicked()),[=](){
exit(0);
});
but still I receive errors indicate "No matching function call".
And after all I have to say that I am using Microsoft Windows 7.
This works on Qt 5.3:
#include <QtWidgets>
void exitToWin()
{
exit(0);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QMessageBox endBox;
endBox.addButton(QMessageBox::Ok); // (2)
endBox.connect(endBox.button(QMessageBox::Ok),
&QAbstractButton::clicked, exitToWin); // (1)
/* This works, too:
endBox.connect(endBox.button(QMessageBox::Ok),
&QAbstractButton::clicked,
[] () { exit(0); });
*/
w.show();
endBox.show();
return a.exec();
}
Here's why:
(1) You can use endBox's QObject to do the connection between the QAbstractButton's clicked signal and your exitToWin simple function. You also can't connect a SIGNAL to a simple function or a lambda, so we use the member function variety, instead.
(2) endBox doesn't actually get an OK button by default. When you mention it on line (1) in your code, it creates it, but not in time (apparently) to pass the pointer back to connect, so we create it first here.
Your code won't work for two reasons:
Firstly, QMessageBox does not have such a signal. See the documentation for the signals it does have.
Secondly, when making connections from a signal to a slot (or lambda function), you must define the function signatures, not specific values.
If a signal can pass a variety of values and you only want your slot to perform a certain function on a selection of those values (in this case, only if the value QMessageBox::Ok is passed) it is up to the slot to interrogate the values, not the connect statement.
Since the connect() method is from QObject it has to be called from a QObject child containing the Q_OBJECT macro in its declaration. Running qmake prepare the class to send signals and receive slots.

How to do things upon quitting a Qt app

To my understanding, the following will execute an application which will exit when all associated windows are closed.
int main(int argc, char *argv[])
{
QApplication cal(argc, argv); //Application instance
MainWindow window; //Create window in the stack
window.show(); //Show the window
return cal.exec(); //Execute event loop
}
This will also quit said application.
quitButton = new QPushButton("Quit", this);
connect(quitButton, SIGNAL(clicked()), QApplication::instance(), SLOT(quit()));
How should I go about cleaning up (closing hardware connections and libraries etc.) so that I can be sure everything that needs to happen happens no matter how the app it exited, nor at what point in execution it is exited?
I will have a library open throughout the whole app, and a connection to a USB device at most times. I am able to close this connection easily if the process runs its course, but I want the connection to be closed safely if somebody decides to hit quit or close all the windows before it is done.
There is a virtual function called closeEvent for a QWidget (see Documentation, which is called when the widgets close() operation is called.
Alternatively, if you don't want to have your own Base widget, you can hook yourself to the signal QApplication::lastWindowClosed (see here). It is emitted when the last visible window of your application closes.
You can do the following:
int main(int argc, char *argv[])
{
QApplication cal(argc, argv);
// Allocate resources
int ret = cal.exec(); // start the event loop and wait until it quits
// Free the resources
return ret;
}
The proper C++ way of doing it is:
Ensuring that all of your object instances get destructed.
Ensuring that any resources you hold are held via RAII.
Then you don't need to do anything special. As the objects get destructed when main returns, things get cleaned up.
For example:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
QObject foo;
QObject * bar = new QObject(&app);
Widget w;
w.show();
return app.exec();
}
Here, both foo and bar are properly destructed before main returns. Now suppose you hold some non-memory resources, like a file:
class Worker : public QObject {
QFile m_file;
...
void doSomething() {
if (m_file.open()) {
...
}
// No file closing!
}
};
int main(int argc, char ** argv) {
QApplication app(argc, argv);
Worker foo;
Widget w;
w.show();
return app.exec();
}
Again, the file gets closed before main returns.
That's how RAII works, in a nutshell. If you have your own classes that wrap OS or other resources, simply ensure that such resources are freed when the classes get destructed - and that the classes are always destructible (it's always safe to destruct them). My pet peeve is QThread - it breaks this expectation, and you have to implement a wrapper to fix it.
For resources that you need to allocate on the heap, you're supposed to be using smart pointers or QObject memory management.
There is a QApplication signal that you can use for cleaning up before the application quits:
QObject::connect(&app, SIGNAL(aboutToQuit()), &MyCleaner, SLOT(cleanUp()));
Have fun!

Qt/C++ : Centralise parameters in one class

I'm trying to centralise some parameters in one class. I looked on several forums and tutorials without finding any real answer. Maybe I don't use Qt correctly.
I have a Qt class Application which handles theses parameters.
Application.h
class Application : public QApplication
{
public:
Application(int, char**);
~Application();
bool setFilesPath(QString path);
QString getFilesPath();
private:
QString filesPath;
}
main.cpp
int main(int argc, char *argv[])
{
Application app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
I'd like to access the setFilesPath() and getFilesPath() methods from everywhere (for exemple in another class. Therefore a made Application inherit from QApplication, hoping that qApp.setFilesPath() would work. But it doesnt.
It seems to be a quite usual thing to access some parameters from everywhere. So how could one do this ?
I've found this three ways :
Global variables
Static methods
Including an instance of Application in every class needing the method (but it seems wrong)
Which is more commonly used (and why) ? Why does my way doesn't work ?
Thank you.
EDIT:
In this topic, they use singelton design pattern.
So calling
Application *app = Application::getInstance();
everywhere I need it. Is it better ?
You can access your class using qApp pointer. According to the Qt documentation:
A global pointer referring to the unique application object. It is
equivalent to the pointer returned by the QCoreApplication::instance()
function except that, in GUI applications, it is a pointer to a
QApplication instance.
So, your code somewhere could look like:
Application *myApp = qobject_cast<Application *>(qApp);
QString path = myApp->getFilesPath();
You can have your classes in the main independently and connect a signal from each class that needs to access the value in your class to the slot that returns the value :
int main(int argc, char *argv[])
{
Application app(argc, argv);
MainWindow mainWindow;
MyClass myclass1;
QObject::connect(&mainWindow,SIGNAL(askFilesPath()),myclass1,SLOT(getFilesPath()));
mainWindow.show();
return app.exec();
}
This way when you call the signal askFilesPath() in your MainWindow, the slot in your custom class gets called and the value is returned:
QString filePath = askFilesPath();
You should note that if the two classes are in different threads then the connection type should be Qt::BlockingQueuedConnection.