Qt 相当于 GObject.idle_add()

Qt equivalent to GObject.idle_add()

在 Qt 中是否有与 Gtk 的 GObject.idle_add() 方法等效的方法?

The gobject.idle_add() function adds a function to be called whenever there are no higher priority events pending to the default main loop.

我的研究让我遇到了一些 QTimer 诡计:

QtCore.QTimer().singleShot(0, self.my_method)

但它看起来有点老套,不是那么简单,这让我觉得它可能不是最好的选择。

有"Qter"解决方案吗?或者我不应该首先这样做吗?

上下文

我的 GUI 具有根据绘图参数起作用的小部件。当小部件为 clicked/edited/whatever 时,我使用 signals/slots 刷新绘图。一个小部件可能会影响其他几个小部件,从而在一次用户单击时触发级联多个刷新操作,因此我正在寻找一种方法来避免在不需要时多次刷新:只有最后一次刷新才有意义。

我尝试在处理此类事件时断开信号,然后在完成后将它们连接回去并调用刷新 "manually"。我还尝试使用一个标志来抑制或多或少等效的刷新方法。这两种方式似乎都复杂得没用。

我在考虑不是将每个小部件连接到 refresh(),而是将它们连接到 refresh_request() 方法,该方法会引发 "refresh request" 标志并将 0 秒计时器设置为如果标志被提升,空闲时执行 refresh_if_needed() 刷新。只会发生一次刷新,因为它只会在事件处理完成时执行。并且只有当至少一个小部件的数据确实被修改时它才会刷新。此外,GUI 可能会让用户感觉更流畅一些,因为事件的处理速度会更快。

编辑

与其让 refresh_request() 提升 "refresh request" 标志并添加一个计时器来处理空闲标志,不如让 refresh_if_needed() 从主循环中永久监视标志,在哪种情况 refresh_request() 只需要处理标志。

这样的设计会更好吗?不确定,但无论如何,我的问题可能是 "how can I add some task to the main loop in Qt?"。这会吃掉所有 CPU 吗?我是否需要添加一个 "manual",500 毫秒左右,在 refresh_if_needed() 中暂停?在这种情况下,我想我可以在正常模式下使用 QTimer 启动它(不是 singleShot),但这是 "normal" 方式吗?

无论如何,我仍然对 idle_add 的等价物感兴趣。我想到的一个用例是我几年前编写的 Gtk GUI。这些按钮启动或停止线程中的声音。为了避免竞争条件,我在主循环中开始和停止声音(code on GitHub(1000 LoC 文件,不是精简的示例))。

相当于 Qt 中的 g_idle_add() 可以通过为您的一个小部件实现自定义事件来实现,该事件通过覆盖接收器的 event() 方法来处理,如 documentation for Qt 5 并且已经在评论中指出了。

一个 Qt 5 示例(Qt 4 与所有这些类似)将是:

// Initialize event type
int customType = QEvent::registerEventType();

// Handle
bool MyWidget::event(QEvent* event) {
    if (event->type() == (QEvent::Type) customType) {
        // TODO: Do whatever your idle callback would do

        // Optional: Post event again to self if this should be repeated
        //           implementing behaviour of returning TRUE from g_idle_add callback

        return true;
    }

    // Else default handler, may want to replace QWidget with actual base of "MyWidget"
    return QWidget::event(event);
}

// Emit (given this is of type MyWidget)
QApplication::postEvent(this, new QEvent((QEvent::Type) customType));

但是,如果目标只是始终将信号处理推迟到主循环,就像 OP 的问题一样,那么有一个更简单的选择。连接槽和信号时,为QObject::connect()type参数指定Qt::QueuedConnection。记录了不同的连接类型 here.