Qt - Close app if QInputDialog canceled [duplicate] - c++

Why does this program run normally and display the main window? I would expect it to exit since quit() is called in the constructor.
Main.cpp:
#include<QApplication>
#include"MainWindow.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
qApp->quit();
}
void MainWindow::closeEvent(QCloseEvent *)
{
qDebug("Hello world!");
}

Since QCoreApplication::quit() is a no-op until the event loop has been started, you need to defer the call until it starts. Thus, queue a deferred method call to quit().
The following lines are functionally identical, either one will work:
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
//or
QTimer::singleShot(0, qApp, SLOT(quit()));
// or - see https://stackoverflow.com/a/21653558/1329652
postToThread([]{ QCoreApplication::quit(); });
// or
QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);

Calling QCoreApplication::quit() is the same as calling QCoreApplication::exit(0).
If you look at the docs of the latter function:
After this function has been called, the application leaves the main
event loop and returns from the call to exec(). The exec() function
returns returnCode. If the event loop is not running, this function
does nothing.
In you example, the event loop has not been started yet when MainWindows constructor is called, hence the call to quit() does nothing.

Related

How can I call a member function of an object in main.cpp from a Qt button?

I am using Qt and have a start/stop button on the GUI. When the application opens, I call some code like this in my main.cpp file:
QApplication a(argc, argv);
MainWindow w;
w.show();
Something something;
something.start();
In the mainwindow.cpp file that was created by Qt, I have this function that is called when the stop button is pressed:
void MainWindow::on_pushButton_2_released()
{
std::cout << "stopped" << std::endl;
}
How can I call something.stop() from void MainWindow::on_pushButton_2_released()? Or how can I restructure my code so that I can access that class instance?
There are many approaches to this problem, and it depends on what exactly the structure of this program should look like. One simple way would be to add a constructor to the MainWindow class that takes a pointer to something and stores that pointer as a member, i.e.
class MainWindow : public QMainWindow
{
public:
...
MainWindow(Something* something) : something_ptr(something)
{
...
}
...
private:
Something* something_ptr;
...
void MainWindow::on_pushButton_2_released()
{
something_ptr->stop();
}
}
then from your main function:
QApplication a(argc, argv);
Something something;
MainWindow w(&something);
something.start();
w.show();
Since you probably call a.exec() after this, something will exist until the application exits (since exec() is a blocking call).

Application not quit when sending QApplication::exit or QApplication::quit [duplicate]

Why does this program run normally and display the main window? I would expect it to exit since quit() is called in the constructor.
Main.cpp:
#include<QApplication>
#include"MainWindow.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
qApp->quit();
}
void MainWindow::closeEvent(QCloseEvent *)
{
qDebug("Hello world!");
}
Since QCoreApplication::quit() is a no-op until the event loop has been started, you need to defer the call until it starts. Thus, queue a deferred method call to quit().
The following lines are functionally identical, either one will work:
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
//or
QTimer::singleShot(0, qApp, SLOT(quit()));
// or - see https://stackoverflow.com/a/21653558/1329652
postToThread([]{ QCoreApplication::quit(); });
// or
QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
Calling QCoreApplication::quit() is the same as calling QCoreApplication::exit(0).
If you look at the docs of the latter function:
After this function has been called, the application leaves the main
event loop and returns from the call to exec(). The exec() function
returns returnCode. If the event loop is not running, this function
does nothing.
In you example, the event loop has not been started yet when MainWindows constructor is called, hence the call to quit() does nothing.

C++ application does not kill all processes on exit

This is my main.cpp which starts the mainwindow:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabWindow w;
w.show();
return a.exec();
}
Even with the a.connect(...) I do not understand why myApplication.exe still runs after I close the mainwindow. Any suggestions on how I can fully end all processes after the quit button is clicked?
EDIT: The Qt Documentation says this:
We recommend that you connect clean-up code to the aboutToQuit() signal, instead of putting it in your application's main() function. This is because, on some platforms, the QApplication::exec() call may not return.
There's nothing wrong with your code. And your connect doesn't do anything.
Unless you call QGuiApplication::setQuitOnLastWindowClosed(true) somewhere, application should exit when the last window is closed. Probably you block event loop somewhere in your window code.
Thanks to the comment posted by #ratchetfreak in my question, I figured out where the problem was.
In my MainWindow, I started a worker thread which was not terminated and thus still persisted as a process after the application was closed. In order to fix this, I registered the close event and kept track of the existence of the thread - i.e. basically, ignored the closeEvent until the thread was deleted as well.
void MainWindow::closeEvent(QCloseEvent *event)
{
if (workerThreadExists) {
// Gracefully exiting all tasks inside the worker thread
while (workerThreadExists){
event->ignore();
}
event->accept();
}
}
...and for me workerThreadExists is just a BOOLEAN that is set to true once the thread is created and then it is set to false when the thread is deleted. Hope this helps!
You should have something like this:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabWindow w;
w.show();
return a.exec();
}
// Do quit in your TabWindow:
TabWindow::TabWindow()
: public QWidget(NULL)
{
connect( ui->myQuitButton, SIGNAL( clicked() ), qApp, SLOT( quit() ) );
}
just replace
return a.exec();
with
return 0;
That should end all processes which is associated with that program.

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!

How to programmatically click a QPushButton

I am using Qt. I have a button in the page added via the Qt Creator. It is connected to the method void MyPage::on_startButton_clicked().
I want to programmatically click this button. I tried ui->startButton->clicked(), it gives,
error C2248: 'QAbstractButton::clicked' : cannot access protected member declared in class 'QAbstractButton'
Please help. Thanks!
Use QAbstractButton::animateClick():
QPushButton* startButton = new QPushButton("Start");
startButton->animateClick();
RA's answer provides the way to do it so that it's visible that the button was clicked. If all you wish for is to emit the signal, what you're doing is correct in Qt 5, where the signals are public.
The error you're facing indicates that you're using Qt 4, where the signals are not public. You can work around this by invoking the signal indirectly:
QMetaObject::invokeMethod(ui->startButton, "clicked");
This calls the method immediately, i.e. the signal will be dispatched and the slots called by the time invokeMethod returns. Alas, most code (mostly your code!) assumes that the signal is emitted from event processing code close to the event loop - i.e. it's not reentrant, rather than from your own code. Thus you should defer the signal emission to the event loop:
// Qt 5.4 & up
QTimer::singleShot(0, ui->startButton, [this]{ ui->startButton->clicked(); });
// Qt 4/5
QTimer::singleShot(0, ui->startButton, "clicked");
The following is a complete example for Qt 5.4 & up:
#include <QtWidgets>
int main(int argc, char ** argv) {
bool clicked = {};
QApplication app{argc, argv};
QPushButton b{"Click Me"};
QObject::connect(&b, &QPushButton::clicked, [&]{ clicked = true; qDebug() << "clicked"; });
Q_ASSERT(!clicked);
b.clicked(); // immediate call
Q_ASSERT(clicked);
clicked = {};
// will be invoked second - i.e. in connect order
QObject::connect(&b, &QPushButton::clicked, &app, &QApplication::quit);
QTimer::singleShot(0, &b, [&]{ b.clicked(); }); // deferred call
Q_ASSERT(!clicked);
app.exec();
Q_ASSERT(clicked);
}
If you do not want the animation stuff, you can also just call the method:
on_startButton_clicked();