Qt: event loop during closing - c++

According this article here, is it Ok to say that, when we close a Qt programm. Once the mainWindow's close event started, nothing else except the close event handler and class deconstructor in the GUI thread will be executed?
For example, if there is a QTimer fired the timeout() signal in the GUI thread to a slot in the same thread. When the mainWindow's close event started, the slot will not get any chance to be executed again?

No, it is wrong on its face to say that once the mainWindow's close event started, nothing else will execute in the GUI thread except the close event handler and class destructors.
Suppose we have following code (in C++11):
#include <QApplication>
#include <QLabel>
#include <QMessageBox>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label1("Hello, World!");
label1.show();
label1.setMinimumSize(200, 100);
app.exec();
QTimer timer;
int counter = 0;
QObject::connect(&timer, &QTimer::timeout, [&counter]{ counter ++; });
timer.start(100);
QMessageBox::information(nullptr, "Done",
QString("We're Done with \"%1\"").arg(label1.text()));
QMessageBox::information(nullptr, "Really Done",
QString("Timer has ticked %1 times").arg(counter));
return 0;
}
Obviously, non-destructor code will execute after exec() has returned - here we show a message box. The main window, in this case a QLabel, still exists after exec() has returned.
It is also incorrect to assume that somehow the timers will be globally killed after exec() has returned. They're still running, and as long as you re-start the event loop, they'll gladly fire for you. The second message box will display a non-zero count, after all.
Your question should be reworded with the problem you're trying to solve. You're asking for very specific details that make little sense on their own. Please tell use why you ask such a question.

It's handled automatically:
QObject::~QObject()
All signals to and from the object are automatically disconnected, and
any pending posted events for the object are removed from the event
queue. However, it is often safer to use deleteLater() rather than
deleting a QObject subclass directly.
However for multi-threaded apps you need to use deleteLater() to avoid crashes:
Warning: Deleting a QObject while pending events are waiting to be
delivered can cause a crash. You must not delete the QObject directly
if it exists in a different thread than the one currently executing.
Use deleteLater() instead, which will cause the event loop to delete
the object after all pending events have been delivered to it.

Related

Input widget in QApplication in a dedicated thread causes QTimer to be stopped from the wrong thread

For different reasons I have to create a QApplication that does not live in the main thread of my program. This works well except for the cleanup part. Once main() finishes I get the following notification:
QObject::~QObject: Timers cannot be stopped from another thread
This happens quite some time after all Qt widgets and windows as well as the QApplication have been disposed of.
I narrowed the problem down to this minimal example:
#include <thread>
#include <QApplication>
#include <QLineEdit>
int main(int argc, char * argv[])
{
std::thread t {
[&] {
QApplication app{argc, argv};
QLineEdit w{"Test"};
w.showNormal();
app.exec();
}
};
std::this_thread::sleep_for(std::chrono::seconds{3});
QApplication::instance()->quit();
t.join();
return 0;
}
A QSpinBox instead of a QLineEdit leads to the same behavior. When I use a QLabel however, no warning is issued. So I suspect that the culprit is a timer responsible for cursor flashing but I might be wrong here.
Is there any way to stop this (invisible) timer correctly when quitting the QApplication?
I would also be happy with manually posting something like a QuitEvent
in the application's event loop instead of calling quit()directly.
Here you go:
QMetaObject::invokeMethod(QApplication::instance(), "quit", Qt::QueuedConnection);
You are not allowed to access widgets and other related elements from anywhere but the main thread. This is common with nearly all GUI systems (e.g. MFC, BGI, ...).
For Qt there is a hint on this in the documentation. Surprisingly enough not even a QPixmap is allowed in worker threads.

QApplication::exec() refuses to return (in console program)

I have a Qt C++ program that, although it isn't actually using a GUI (with the exception of a few message box popups) makes use of the QApplication::exec()
method (necessary so the event loop is run and can service the whole signal/slot business). I'm also calling QApplication::setQuitOnLastWindowClosed( false ) because otherwise the program would end immediately when the user dismisses one of the message box popups. I don't think this should have any influence on the behavior I'm observing, but I'm mentioning it anyway, just in case.
At some point, of course, the program should end, and I have added a call to QApplication::exit() to cause Qt to fall out of its event loop and thus return from the QApplication::exec() call. According to the Qt documention on the QApplication::exec() method, this is precisely what should happen.
int QApplication::exec()
Enters the main event loop and waits until exit() is called, then
returns the value that was set to exit() (which is 0 if exit() is
called via quit()).
However, in my program it's just not happening. I've traced the program flow in a debugger and I know for sure that QApplication::exit() is called, but still QApplication::exec() doesn't seem to want to return. :(
I'm using Qt 5.4.1 with MinGW 3.11 (the GCC compiler identifies itself as version 4.9.1). My computer is running Windows 7 Enterprise (64 bit), Service Pack 1. Does anyone know what I might be doing wrong?
EDIT: Kuba Ober mentioned in his comment that QApplication::exec() is probably not returning because my code is blocking somewhere. I'd like to post this screenshot of the main thread's call stack to prove that the main thread is stuck deep inside the guts of Qt at this point and that my own code is not in fact in control.
SOLUTION: Ok, Rudolfs Bundulis' answer led me to the root of the problem. I had a little message box in my program that pops up and asks the user to perform a certain action (in this case, to switch on an external device that communicates with my program). For the program flow to continue, it is not necessary to dismiss this popup; it is sufficient to simply turn on the external device, and so I forgot to dismiss the message box and just left it alone. Later, when QApplication::exit() is called, Qt seems to destroy the message box (or at least make it invisible) so it can no longer be dismissed, and as Rudolfs Bundulis has pointed out, an open message box is enough to keep QApplication::exec() from returning.
The mechanism you described should work. Here is a small snippet with two ways of terminating a QApplication just the way you inteded - either via a direct the QApplication::quit() slot or the QApplication::exit() call. Both seem to work.
QApplicationTerminator.h:
#pragma once
#include <QObject>
#include <QDebug>
#include <QApplication>
class QApplicationTerminator : public QObject
{
Q_OBJECT
public slots:
void quit()
{
qDebug() << "terminating QApplication\n";
QApplication::exit(0);
}
};
main.cpp:
#include "qapplicationterminator.h"
#include <QApplication>
#include <QTimer>
#include <QDebug>
#include <QThread>
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
QApplicationTerminator terminator;
QTimer::singleShot(3000, &application, SLOT(quit()));
//QTimer::singleShot(3000, &terminator, SLOT(quit()));
application.setQuitOnLastWindowClosed(false);
auto result = application.exec();
qDebug() << "event loop exited\n";
return result;
}
I'll have to agree with #KubaOber that most likely you are either blocking somewhere.
Since you mentioned dialogs - dialogs run their own event loop, if any of the event loops of your dialogs are still running (this however should not happen if they are properly used) the main event loop simply does not get back in control and cannot exit.

QT - force an object to process incoming signals

I am wondering how to tell a QObject to process all signals and call the slots associated with them. Here's the concrete problem I am having, for a better description of the question:
My program consists of three Qthreads : Main, Communication and Input.
The communication thread handles communication via the network, the Input thread handles user input, and both have several signal-slot connections to the main thread. Whenever a network event occurs, or whenever the user inputs a commandline command, a signal from the respective thread is called, which then activates the appropriate connected slot in the main thread. The main thread's role is to process these events. My code looks as follows:
QApplication a(argc, argv);
CommObj co; //inherits from QThread
co.start(); //Starts the thread
InputObj io; //inherits from QThread
io.start(); //Starts the thread
MainObj u(&co,&io);
return a.exec();
Now, what I want to achieve is for the main thread to not reach the last line.
My intentions are to call a method run() within the constructor of MainObj which is going to do something along the lines of this:
void run ()
{
forever
{
//process all signals..
}
}
However, I do not know how to implement the process all signals part. Any advice on how this could be done (including workarounds) would be very welcome.
This is completely unnecessary. a.exec() runs an event loop that will receive and process the events sent by other threads.
When a slot is invoked due to a signal being emitted in a different thread, Qt is posting a QMetaCallEvent to the receiver object. The QObject::event method is able to re-synthesize the slot call based on the data in the event.
Thus, you need to do nothing. a.exec() does what you want. Feel free to invoke it from MainObj's constructor, as qApp->exec() or as QEventLoop loop; loop.exec(), but that's rather bad design.
The real questions are:
Why do you need MainObj's constructor to spin an event loop?
What sort of "user input" are you processing in the io? You can't access any GUI objects from that thread.
Why are you deriving from QThread if you're using Qt's networking? You definitely don't want to do that - it won't work unless you spin an event loop, so you might as well just use a QThread without changes. Well, to be safe, you need just to make the thread destructible, so:
class Thread {
using QThread::run; // make it final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { requestInterruption(); quit(); wait(); }
};
Anyway, by not using standard QThread that spins an event loop, the communication will be one way. Nothing in such threads will be able to react to signals from other threads.
You need to rearchitect as follows:
Use the Thread class as above. It's safe to be destructed at any time.
Have worker objects that run asynchronously using signals/slots/timers.
Move constructed workers to their threads.
What you need is the processEvents function. For example, if you don't want the user to be able to interact with widgets, but you want the graphics to update, use
processEvents(QEventLoop::ExcludeUserInputEvents);
See the documentation for details.

Printing to an element of MainWindow from an outside class

I have created a set of watcher/helper classes that monitor an outside application, and I would like these to print to a log window inside my MainWindow's ui when changes are made. My idea was to create this watcher inside a thread in main, but I am not sure the best way to link it to my MainWindow. I know that simply passing it as below will not work, but am unsure of the proper way to do this, if there even is one, because of Qt's design. Some research indicated to me that it isn't really appropriate to pass MainWindow to an outside class, but I am unsure of a better way to do it.
int main(int argc, char *argv[])
{
try {
std::string host = "localhost";
unsigned short port = 8193;
MainWindow w;
w.show();
// Access class for the program that I am watching
UserInterface ui(host, port);
// StatePrinter class, which is registered in the UI and will print changes to MainWindow, ideally
// would I be able to pass something in the StatePrinter constructor to accomplish my goal?
ui.registerObserver(new StatePrinter(w));
UiRunner runner(ui);
boost::thread runnerThread(boost::ref(runner));
w.show();
QApplication a(argc, argv);
runner.cancel();
runnerThread.join();
return a.exec();
} catch(std::exception &ex) {
// ...
}
}
I suppose it is a possibility to make this thread inside MainWindow itself, but I prefer having it in main. What would be the best way to link my StatePrinter class to MainWindow?
You could make your watcher class a QObject itself, push it into a thread, and make it emit signals when it "notices" changes that you want to log with the log informations as the signal parameters.
Then, you could push this object in a QThread as follow :
QThread* thread = new QThread();
ui->moveToThread(thread);
//Create the needed connections
thread->start();
Depending on what you need, you may connect a signal to the thread's start() slot instead of calling it directly. (Read this to know which connections you'll need with your thread so it is started, stopped and cleaned correctly).
You have several problems:
Creating widgets before instance of QApplication
runnerThread.join call will block main Qt thread before entering Qt event loop - so your GUI will be freezed
You should implement notification system to watch for termination of boost threads. But better solution is to use Qt threads.
You should create first class - "watcher" with neccessary signals.
Then create second class with UI logic and neccessaty slots
Then connect signals to slots
Profit!
Look at Qt documentation about QThread - there are simple samples.

Using Qt where worker thread creates new GUI elements

I will keep the code simple so that you guys can see what I'm trying to do ;)
I am aware of all of the locking issues, etc. I'm trying to figure out how signals and slots play with threads.
In main.cpp:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyConsole c; // Subclasses QThread and implements run()
MyReceiver r(app); // We pass app to MyReceiver for later (see below)
QObject::connect(&c, SIGNAL(sendit()),
&r, SLOT(gotit()));
c.start(); // Start the worker thread
app.exec();
}
Assume that the signals and slots were properly set up in the header files (I've tested and they are). Now, here's the issue:
In MyReceiver.cpp:
void MyReceiver::gotit()
{
QLabel *label = new QLabel(0, "Hello"); // Some GUI element, any will do
app.setMainWidget(*label); // Some GUI action, any will do
}
The question is: Because the MyReceiver object was created in main(), which is on the main thread, does that mean that the slots (e.g., gotit()) will run on the main thread and are therefore safe for doing GUI stuff? Even in cases where the signal was raised from a different QThread (like MyConsole in this example)?
Is there a better way to allow worker threads to interact with the GUI (for example, Obj-C/Cocoa have a "send message on main thread" type of approach). What is "The Qt way" of doing this?
Thanks in advance!
By default (Qt::AutoConnection), slots will run in the thread the QObject was created in. So, no matter from what thread you emit the signal, the slot will be run always in the thread, the QObject "lives" in (if a Qt event loop is running in that thread, otherwise the event can't be delivered). Since the main thread will become the Qt GUI thread, this will work as expected. This is indeed the Qt way of interacting with the GUI.
See also: http://doc.qt.nokia.com/4.7/thread-basics.html (look for thread affinity).
The "Qt way" to emit a signal from one thread and receive it in a different thread is to use a Queued connection
connect( obj, SIGNAL(foo()), other_obj, SLOT(bar()), Qt::QueuedConnection )
From the Qt documentation for Qt::QueuedConnection:
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.