In some Qt examples, I see they use
QTimer::singleShot(0, this , SLOT(funcA()))
, why not to call the slot funcA
directly? also the same question for using QMetaMethod::invoke
to call function with parameters.
[static] void QTimer::singleShot(int msec, const QObject *receiver, const char *member) This static function calls a slot after a given time interval. It is very convenient to use this function because you do not need to bother with a timerEvent or create a local QTimer object.
The QTimer class provides a high-level programming interface for timers. To use it, create a QTimer, connect its timeout() signal to the appropriate slots, and call start(). From then on, it will emit the timeout() signal at constant intervals.
The following lines are all functionally equivalent:
QTimer::singleShot(0, object, &Class::funcA); // Qt 5
QTimer::singleShot(0, object, SLOT(funcA())); // Qt 4
QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection);
As is now apparent, the intent is to execute the call within the event loop. The queued call results in the posting of an QMetaCallEvent
to the object
. This event is handled by QObject::event
and results in the call of the desired method. Thus, the following are exactly equivalent, even if the latter is a private implementation detail - letting me skip the details of instantiating the event:
QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection);
QCoreApplication::postEvent(object, new QMetaCallEvent{...});
This comes handy in various situations. For example:
To execute some code after all hitherto posted events have been handled.
To execute only after the event loop has started.
To call an invokable method that's not accessible due to C++ access modifiers. The invokable methods are: signals, slot, and methods declared Q_INVOKABLE
.
The direct call is unsafe (read: an error!) when a QObject
resides in another thread, unless you're explicitly calling a method documented as thread-safe.
The queued call is a necessity if you wish to ensure that an event loop quits immediately: a direct quit()
call is a no-op if the loop is not running yet.
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
app.quit(); // this is a no-op since the event loop isn't running yet
return app.exec(); // will not quit as desired
}
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
return app.exec(); // will return immediately
}
Ideally, you'd use postToThread
from this answer, it offers the lowest-cost way of calling methods in other threads:
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
postToThread([]{ qApp->quit(); });
}
An alternative way of doing it is using a QObject
as a signal source:
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
{
QObject src;
src.connect(&src, &QObject::destroyed, &app, &QCoreApplication::quit,
Qt::QueuedConnection);
}
return app.exec(); // will return immediately
}
Yet another way would be to use a custom event and act in its destructor:
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
struct QuitEvent : QEvent {
QuitEvent() : QEvent(QEvent::None) {}
~QuitEvent() { qApp->quit(); }
};
QCoreApplication::postEvent(&app, new QuitEvent);
return app.exec(); // will return immediately
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With