如何访问在Python的另一个线程中实例化的用户定义的QObject

问题描述 投票:0回答:1

我从来没有使用 C++ 遇到过这个问题,但最近我一直在使用 QML/PyQt5/Python 并且遇到了以下错误:

QQmlEngine: Illegal attempt to connect to MyClass(0x1fd42731e50) that is in a different thread than the QML engine QQmlApplicationEngine(0x1fd41562f70.

我有一个工作线程,它创建我定义的QObject。它是由设置为上下文属性的控制器线程生成的。

这是一份 M.R.E.:

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 600
    title: "Clock"


    Text {
        id: backend_data
        anchors.centerIn: parent
        text: backend.my_class.value.toString()
    }
}
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty, QThread, QTimer, pyqtSlot
import sys
import copy

class MyClass(QObject):

    value_changed = pyqtSignal()

    def __init__(self, value):
        QObject.__init__(self)
        self._value = value

    @pyqtProperty(int, notify=value_changed)
    def value(self):
        return self._value

class Worker(QObject):

    my_class_signal = pyqtSignal(QObject)

    def __init__(self, *args, **kwargs):
        QObject.__init__(self, *args, **kwargs)
        self._i = 0
        self.timer=QTimer()
        self.timer.timeout.connect(self.send_my_class)
        self.timer.start(1000)
        self._my_class = MyClass(0) 

    @pyqtSlot()
    def send_my_class(self):
        self._i += 1
        self._my_class = MyClass(self._i)
        self.my_class_signal.emit(self._my_class)

class Backend(QObject):

    my_class_changed = pyqtSignal()

    def __init__(self, *args, **kwargs):
        QObject.__init__(self, *args, **kwargs)
        self._my_class = MyClass(0)
        self._thread = QThread()
        self._worker = Worker() 
        self._worker.moveToThread(self._thread)
        self._worker.my_class_signal.connect(self.receive_my_class)
        self._thread.start()

    @pyqtSlot(QObject)
    def receive_my_class(self, myclass):
        self._my_class = myclass
        self.my_class_changed.emit()

    @pyqtProperty(QObject, notify=my_class_changed)
    def my_class(self):
        return self._my_class

if __name__ == '__main__':
    app = QGuiApplication(sys.argv)
    backend = Backend()
    engine = QQmlApplicationEngine()
    engine.quit.connect(app.quit)
    engine.rootContext().setContextProperty('backend', backend)
    engine.load('./example.qml')
    if len(engine.rootObjects()) > 0:
        sys.exit(app.exec())

我应该采取什么不同的做法?

python qt pyqt5 qml
1个回答
0
投票

python 有一个称为 GIL(全局解释器锁)的功能,它确保一次只能存在 1 个 CPython(python 解释器)实例。即使您使用线程,python 也只是在线程之间传输 CPython 实例,因此仍然只有 1 个解释器在运行。就我个人而言,我喜欢使用另一种语言(如 Rust 或 C++)来处理线程,并将这些线程句柄放置在某种类或函数中。然而,如果你必须只使用 PyQt5,那么我知道很多人喜欢只使用 AsyncIO (PyQt5 的工作效果比线程好得多)。如果你真的想使用线程,那么使用queue

© www.soinside.com 2019 - 2024. All rights reserved.