在Qt(PySide2)中的主线程上调用函数的简单方法



有什么简单的方法可以从任何其他线程或QThread调用主线程中的函数或方法吗?

我听说Slots和Signals可以用作线程和主线程之间的代理,但每次我想将数据传输到主线程时,都要创建这样的代理,这感觉工作量太大了。

(我的答案描述了一种非常通用的方法来处理这个问题,所以我不会在这里提供一个"最小"的例子,你可以看看答案。(

Qt有一个名为invokeMethod的函数(https://doc.qt.io/qt-5/qmetaobject.html#invokeMethod)其可用于通过使用CCD_ 4连接类型来调用主线程上的方法。

然而,在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)

这将在内部创建一个没有任何参数的SignalSlot。然而,Slot将在主线程上被调用,因为它已经使用Qt.AutoConnection(默认值(连接并移动到具有moveToThread(...)的主线程。为了确保没有函数参数因垃圾收集器而丢失,类的父级被临时设置为QGuiApplication实例(如果不依赖QGuiApplication,则可能需要更改此设置。任何QObject都可以作为父级(。

下面是一个关于如何使用这个类的例子:

InvokeMethod(lambda: print("hello"))

最新更新