使用concurrent.futures.ThreadPoolExecutor()时PyQt5小部件

我一直在尝试使用concurrent.futures.ThreadPoolExecutor()在我的应用程序中运行一些后台任务,以便在这些任务(“测量”)运行时我能够与 GUI 进行交互。这些任务完成后,我分配一个回调函数来更新 GUI 的某些字段,然后尝试根据这些字段更新 GUI 小部件(绘图、表格、列表等)。


这是一个例子:


class MainWindow(QtWidgets.QMainWindow):

    

    def __init__(self):

        super(MainWindow, self).__init__()

        *some more code goes here*

        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)


    def perform_measurement():

        future = self.executor.submit(*a function*)

        future.add_done_callback(self.update_gui_fields)


    def update_gui_fields(self, future):

        data = future.result()

        self.items_for_list.append(QStandardItem(data['key']))

        *more fields are updated here*


        self.QListView1.setModel(self.items_for_list)

        *more widgets are updated here*

问题是字段已正常更新,但是当我尝试与小部件交互时,应用程序崩溃了。这是因为子级(此处为)与父级(此处为)self.items_for_list位于不同的线程中。self.QListView1这是我得到的错误:


QObject: Cannot create children for a parent that is in a different thread.

(Parent is QListView(0x555795efbc10), parent's thread is QThread(0x555795296600), current thread is QThread(0x7fd12400a100)

QBasicTimer::start: QBasicTimer can only be used with threads started with QThread

我在之前的帖子中找不到任何解决方案。知道如何攻击这个吗?谢谢!


慕尼黑8549860
浏览 127回答 1
1回答

HUH函数

与 add_done_callback 关联的回调在辅助线程中执行,根据您的代码,您正尝试从该辅助线程更新 GUI,这是禁止的,因此 Qt 会抛出该警告。解决方案是通过创建一个通过信号转发该信息的 QObject 来实现逻辑:import concurrent.futuresimport sysimport timefrom PyQt5 import QtCore, QtGui, QtWidgetsdef measure():    time.sleep(5)    return {"key": "value"}class TaskManager(QtCore.QObject):    finished = QtCore.pyqtSignal(object)    def __init__(self, parent=None, max_workers=None):        super().__init__(parent)        self._executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers)    @property    def executor(self):        return self._executor    def submit(self, fn, *args, **kwargs):        future = self.executor.submit(fn, *args, **kwargs)        future.add_done_callback(self._internal_done_callback)    def _internal_done_callback(self, future):        data = future.result()        self.finished.emit(data)class MainWindow(QtWidgets.QMainWindow):    def __init__(self):        super(MainWindow, self).__init__()        self.model = QtGui.QStandardItemModel()        self.view = QtWidgets.QListView()        self.view.setModel(self.model)        self.button = QtWidgets.QPushButton("launch")        self._manager = TaskManager(max_workers=1)        self._manager.finished.connect(self.update_gui_fields)        self.button.clicked.connect(self.perform_measurement)        central_widget = QtWidgets.QWidget()        self.setCentralWidget(central_widget)        lay = QtWidgets.QVBoxLayout(central_widget)        lay.addWidget(self.view)        lay.addWidget(self.button)    def perform_measurement(self):        self._manager.submit(measure)    def update_gui_fields(self, data):        self.model.appendRow(QtGui.QStandardItem(data["key"]))if __name__ == "__main__":    app = QtWidgets.QApplication(sys.argv)    w = MainWindow()    w.show()    sys.exit(app.exec_())
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python