如何解决在 Qt (PySide2) 的主线程上调用函数的简单方法
有没有什么简单的方法可以从任何其他线程或 QThread 调用主线程中的函数或方法?
我听说 Slot
和 Signal
可以用作线程和主线程之间的代理,但是每次我想要创建这样的代理都感觉工作量太大将数据传输到我的主线程。
(我的回答描述了一种非常通用的方法来实现这一点,所以我不会在这里提供“最小”示例,您可以查看答案。)
解决方法
Qt 有一个名为 invokeMethod
(https://doc.qt.io/qt-5/qmetaobject.html#invokeMethod) 的函数,可用于通过使用 Qt.QueuedConnection
连接类型调用主线程上的方法。
但是在 PySide 如果你想调用一个带参数的函数,这将不起作用!
解决方案:
因此,为了使用 PySide 实现类似甚至更简单的功能,我编写了这个类,每次您想在主线程上运行函数或方法时都可以使用它:
from typing import Callable
from PySide2.QtCore import QObject,Signal,Slot
from PySide2.QtGui import QGuiApplication
class InvokeMethod(QObject):
def __init__(self,method: Callable):
"""
Invokes a method on the main thread. Taking care of garbage collection "bugs".
"""
super().__init__()
main_thread = QGuiApplication.instance().thread()
self.moveToThread(main_thread)
self.setParent(QGuiApplication.instance())
self.method = method
self.called.connect(self.execute)
self.called.emit()
called = Signal()
@Slot()
def execute(self):
self.method()
# trigger garbage collector
self.setParent(None)
这将在内部创建一个没有任何参数的 Signal
和一个 Slot
。但是,Slot
将在主线程上调用,因为它已使用 Qt.AutoConnection
(默认值)连接并使用 moveToThread(...)
移动到主线程。
为确保垃圾收集器不会丢失任何函数参数,类的父类被临时设置为 QGuiApplication
实例(如果您不依赖于 QGuiApplication
. 任何 QObject
都可以作为父级)。
这是一个关于如何使用这个类的例子:
InvokeMethod(lambda: print("hello"))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。