我正在为别人回答我自己的问题,因为很长一段时间没有答案。(我在Qt论坛上发布了同样的问题,但仍然没有答案。参见this https://forum.qt.io/topic/134970/how-to-schedule-a-function-to-run-on-the-main-ui-thread.)
- 一个好的解决方案似乎是这样的。尽管它不是那么简洁,但它使用适当的 Qt API 处理了两个基本问题。
- 从后台线程发布事件是通过以下方式完成的
Signal.emit()
.
- 在空闲时间运行代码是通过
QTimer.singleShot()
.
from PySide2.QtCore import QObject, Signal, QTimer
class IdleRunner(QObject):
run = Signal(object, tuple, float)
def __init__(self):
super().__init__()
self.run.connect(self.on_run)
def on_run(self, func, args, delay):
QTimer.singleShot(delay * 1000, lambda: func(*args))
_idle_runner = IdleRunner()
def run_on_idle(func, *args, delay = 0):
_idle_runner.run.emit(func, args, delay)
-
我们使用上述解决方案大约 6 个月。到目前为止,还没有出现内存泄漏或性能瓶颈等已知问题。
-
9 个月后,我找到了一个更有效的解决方案,通过后台线程发布事件QCoreApplication.postEvent()
。 (现在感觉不那么老套了。)以下是支持关键字参数的更扩展的示例。此外,您还可以轻松地将其应用到PyQt5
通过改变PySide2
在导入语句中PyQt5
.
from PySide2.QtCore import QObject, QEvent, QTimer, QCoreApplication
class IdleRunner(QObject):
def customEvent(self, e):
QTimer.singleShot(int(e.delay * 1000), e.func)
_idle_runner = IdleRunner()
def run_on_idle(func, *args, delay = 0, **kwargs):
e = QEvent(QEvent.User)
e.delay, e.func = delay, lambda: func(*args, **kwargs)
QCoreApplication.postEvent(_idle_runner, e)