【发布时间】: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。