QTimer::singleShot 和 QMetaMethod::invoke

标签 qt

在一些 Qt 示例中,我看到他们使用 QTimer::singleShot(0, this , SLOT(funcA())),为什么不直接调用槽funcA?使用 QMetaMethod::invoke 调用带参数的函数也是同样的问题。

最佳答案

以下几行在功能上都是等效的:

QTimer::singleShot(0, object, &Class::funcA); // Qt 5
QTimer::singleShot(0, object, SLOT(funcA())); // Qt 4
QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection); 

现在很明显,其目的是在事件循环内执行调用。排队的调用会导致将 QMetaCallEvent 发布到对象。该事件由QObject::event 处理并导致调用所需的方法。因此,以下内容完全等效,即使后者是私有(private)实现细节 - 让我跳过 the details of instantiating the event :

QMetaObject::invokeMethod(object, "funcA", Qt::QueuedConnection);
QCoreApplication::postEvent(object, new QMetaCallEvent{...});

这在各种情况下都很方便。例如:

  • 在处理所有迄今为止发布的事件后执行一些代码。

  • 仅在事件循环启动后执行。

  • 调用由于 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
}

理想情况下,您可以使用 this answer 中的 postToThread ,它提供了在其他线程中调用方法的最低成本的方式:

int main(int argc, char ** argv) {
  QCoreApplication app{argc, argv};
  postToThread([]{ qApp->quit(); });
}

另一种方法是使用 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
}

另一种方法是使用自定义事件并在其析构函数中执行操作:

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
}

关于QTimer::singleShot 和 QMetaMethod::invoke,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24142450/

相关文章:

c++ - CMake 使用预处理器定义有条件地添加 Qt 信号

c++ - 如何从 QPlainTextEdit 中读取特定行

android - 通过 JNI 调用简单的 java 静态方法不起作用,尽管 C++ 编译并运行它

qt - 组合框中的项目更改时如何调用函数?

c++ - QUiLoader : requirements for loading . 带有自定义小部件的 ui 文件?

qt - Qt Fresh Gui应用程序在启动时崩溃,并在QtCore4.dll上出错

android - 如何在 Android 上部署 Qt 图像格式插件

qt - 当对象变为无线程时,如何防止 QBasicTimer::stop: Failed 警告?

c++ - QProgressBar 连接类之间的进度 - "no matching function for call"

c++ - Qt+Opencv中导入Gstreamer视频