【问题标题】:Qt equivalent to GObject.idle_add()Qt 等价于 GObject.idle_add()
【发布时间】:2015-05-04 13:20:23
【问题描述】:

Qt中是否有相当于Gtk的GObject.idle_add()方法?

gobject.idle_add() 函数添加了一个函数,当默认主循环没有挂起的更高优先级事件时调用该函数。

我的研究让我发现了一些 QTimer 诡计:

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

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

有“Qter”解决方案吗?还是我不应该一开始就这样做?

上下文

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

我尝试在处理此类事件时断开信号,然后在完成后将它们连接回来并“手动”调用刷新。我还尝试使用标志来禁止或多或少等效的刷新方法。两种方式都显得毫无意义的复杂。

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

编辑

与其让refresh_request() 提高“刷新请求”标志并添加一个计时器来处理空闲的标志,我可以让refresh_if_needed() 永久地从主循环中观察标志,在这种情况下refresh_request() 只会必须处理国旗。

这会是更好的设计吗?不确定,但无论如何,我的问题可能是“如何在 Qt 的主循环中添加一些任务?”。这会吃掉所有的CPU吗?我是否需要添加一个“手动”,大约 500 毫秒,在refresh_if_needed() 中暂停?在这种情况下,我想我可以在正常模式下使用QTimer 启动它(不是singleShot),但这是“正常”方式吗?

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

【问题讨论】:

  • 这听起来可能是过早/毫无意义的优化。你有没有做过任何时间或分析来检查这是否有任何实际的区别?如果没有一个具体的测试用例来证明一个可衡量的问题,这个问题目前几乎是题外话。
  • 我提出的问题(idle_add 等效项)可能与我的上下文无关,但它本身是否可能是题外话?
  • 在我的慢速虚拟机上,绘图刷新时间很明显,但在更好的机器上可能会更快。反正根据数据可能会更长,就算不是,也可惜刷新几次就够了不是吗?正因为如此,我认为我当前的代码设计得很糟糕,我正在寻找一种方法来正确地做到这一点。对于接管的人来说很容易掌握,所以我宁愿坚持经典的 Qt 功能,也不愿增加太多的复杂性。也许这个问题太宽泛而无法成为话题,更像是通用设计模式,而不是与特性/功能相关的。
  • 我会说这只是一个“遗憾”,如果:(a)它使用户界面显着变慢,或者(b)解决它会使实现变得不必要地复杂.如果这些事情都不是真的,那么我可能会接受多次刷新是最不糟糕的解决方案,然后就这样了。但是,当然,这一切都取决于实际代码的细节,这是我之前评论的重点。至于idle_add:我想你可以看看posting a custom event with a low priority

标签: qt4 pyqt4


【解决方案1】:

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

【讨论】:

  • +1。我前段时间问过这个问题,我现在没有做这个。我没有时间测试、验证和接受答案,但无论如何都是有用的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
  • 2020-09-14
  • 2013-12-19
  • 2023-04-11
  • 2014-04-14
  • 1970-01-01
相关资源
最近更新 更多