在一些Qt示例中,我看到他们使用
QTimer::singleShot(0, this , SLOT(funcA())),为什么不funcA直接调用插槽?用于QMetaMethod::invoke调用带参数的函数也是同样的问题.
Rei*_*ica 23
以下几行在功能上都是等效的:
QTimer::singleShot(0, object, &Class::funcA); // Qt 5
QTimer::singleShot(0, object, SLOT(funcA())); // Qt 4
QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection);
Run Code Online (Sandbox Code Playgroud)
现在很明显,目的是在事件循环中执行调用.排队的呼叫导致发布QMetaCallEvent到object.此事件由QObject::event所需方法调用并导致调用所需方法.因此,以下内容完全等效,即使后者是私有实现细节 - 让我跳过实例化事件的细节:
QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection);
QCoreApplication::postEvent(object, new QMetaCallEvent{...});
Run Code Online (Sandbox Code Playgroud)
这在各种情况下都很方便.例如:
在处理了所有迄今发布的事件之后执行一些代码.
仅在事件循环开始后执行.
调用由于C++访问修饰符而无法访问的可调用方法.可调用的方法是:声明的信号,槽和方法Q_INVOKABLE.
当一个QObject驻留在另一个线程中时,直接调用是不安全的(读取:错误!),除非您明确调用记录为线程安全的方法.
如果您希望确保事件循环立即退出,则排队调用是必需的:quit()如果循环尚未运行,则直接调用是无操作.
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
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,你会使用postToThread从这个答案,它提供调用其他线程方法的成本最低的方式:
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
postToThread([]{ qApp->quit(); });
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用a QObject作为信号源:
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
}
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用自定义事件并在其析构函数中执行操作:
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
}
Run Code Online (Sandbox Code Playgroud)