我已经看到了两种不同的方式来启动 Qt 控制台应用程序,即在事件循环启动时调用类方法。 This way一旦事件循环开始,将要调用的方法排队,this way运行一个 singleShot 计时器,该计时器在事件循环开始后不久触发一个插槽执行。在这两种情况下,目标都是在执行类方法之前让事件循环运行。
这些对我来说似乎都不是特别干净,但我没有看到更好的东西。我对 Qt 也没有太多经验,那我该说谁呢?
无论哪种方式都有优势吗? invokeMethod 方式(第一个链接)似乎不像 singleShot 计时器方式(第二个链接)那样常见,但除此之外,我没有理由遵循一种模式而不是另一种模式。
谢谢!
最佳答案
QTimer::singleShot()
有一个采用函数指针(成员函数、仿函数或 lambda)的重载。
使用此重载将提供编译时检查,这比使用函数名称时获得的运行时检查要好。此外,被调用的函数不需要是插槽。
从 Qt 5.8 开始,QMetaObject::invokeMethod()
没有这样的重载。所以你被困在使用他们的名字来调用插槽。请注意,此功能将在 Qt 5.10 中添加。
恕我直言,编译时间检查足以使用 QTimer::singleShot()
(将 QMetaObject::invokeMethod()
放在一边,直到 5.10 结束)。
同样正如@Jeremy 指出的那样,调用 QTimer::singleShot()
以 0 毫秒的延迟结束调用 QMetaObject::invokeMethod()
,但前提是您使用的是采用插槽名称的重载(因此没有编译时检查)。 QTimer::singleShot()
的过载采用函数指针的函数在 0 ms 的情况下没有这种优化,并且可能需要更多的 CPU 和内存来设置。
总结一下:
MyObject *object;
// 1: No compile time check for slot1, may fail at run time if slot1() does not exist
QMetaObject::invokeMethod(object, "slot1", Qt::QueuedConnection);
// 2: Calls 1 internally, but needs to do dome string editing to remove the decoration added by SLOT()
QTimer::singleShot(0, object, SLOT(slot1()));
// 3: Compile time check (i.e slot1() must exist), but creates a QSingleShotTimer internally (maybe less optimized)
QTimer::singleShot(0, object, &MyObject::slot1);
// QTimer::singleShot(0, [&](){printf("\o/"); object->slot1();}); // It can also call lambda
// In any case, slot1 will be called as soon as event processing starts
app.exec()
关于c++ - 启动 Qt5 控制台应用程序 : invokemethod vs singleshot timer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43671504/