繁体   English   中英

Python PyQt5 线程 QObject:无法为不同线程中的父级创建子级

[英]Python PyQt5 threading QObject: Cannot create children for a parent that is in a different thread

我在 Windows 10 计算机上使用 Python 3.7.6 和 PyQt5。 我正在尝试编写一个简单的应用程序,它将同时运行三个不同的过程,在同一窗口的三个单独的文本框中显示输出。 我试图创建一些简单的基本代码来添加,但是在使用 PyQt5 的线程模块时遇到了问题。 这是我的代码:

import sys, time
from threading import Thread

from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QPlainTextEdit, QHBoxLayout
    )

def run1():
    for i in range(20):
        text_1.setPlainText(text_1.toPlainText()  + (f"{i}\n"))
        time.sleep(0.0125)

def run2():
    for i in range(20):
        text_2.setPlainText(text_2.toPlainText()  + (f"{i}\n"))
        time.sleep(0.0125)

def run3():
    for i in range(20):
        text_3.setPlainText(text_3.toPlainText()  + (f"{i}\n"))
        time.sleep(0.0125)

app = QApplication([sys.argv])
win = QMainWindow()

text_1 = QPlainTextEdit()
text_2 = QPlainTextEdit()
text_3 = QPlainTextEdit()

my_widget = QWidget()
my_widget.layout = QHBoxLayout()
my_widget.layout.addWidget(text_1)
my_widget.layout.addWidget(text_2)
my_widget.layout.addWidget(text_3)
my_widget.setLayout(my_widget.layout)

win.setCentralWidget(my_widget)

t1 = Thread(target=run1)
t2 = Thread(target=run2)
t3 = Thread(target=run3)

t1.start()
t2.start()
t3.start()

t1.join()
t2.join()
t3.join()

win.show()

sys.exit(app.exec_())

当我运行此代码时,它显示了所需的输出,但出现以下错误的多个实例:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x166abf795e0), parent's thread is QThread(0x166a9bb0fb0), current thread is QThread(0x166abf56000)

我想我知道为什么会这样,但不知道如何解决。 我认为我应该使用 PyQt5 自己的 QThread 类,但无法理解如何去做。 目前,我将只运行我的三个独立的基于文本的 Python 应用程序,每个应用程序在自己的窗口中显示其输出,但我更喜欢一个基于 GUI 的应用程序,其中包含所有三个。

问题与是否使用QThread无关。 问题是 GUI 元素(例如 QWidget、QTextDocument 等)不是线程安全的,因此您不应修改它们或在与主线程不同的线程中创建它们。 为了在我的解决方案中强调我最初的评论,我不会使用 QThread,但我会继续使用线程,但我会通过信号将信息发送到主线程(如果它们是线程安全的呢):

import sys, time
from threading import Thread

from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import (
    QApplication,
    QMainWindow,
    QWidget,
    QPlainTextEdit,
    QHBoxLayout,
)


class Worker(QObject):
    messageChanged = pyqtSignal(str)

    def start(self, fn):
        Thread(target=self._execute, args=(fn,), daemon=True).start()

    def _execute(self, fn):
        fn(self)

    def write(self, message):
        self.messageChanged.emit(message)


def run1(worker):
    for i in range(20):
        worker.write(f"{i}\n")
        time.sleep(0.0125)


def run2(worker):
    for i in range(20):
        worker.write(f"{i}\n")
        time.sleep(0.0125)


def run3(worker):
    for i in range(20):
        worker.write(f"{i}\n")
        time.sleep(0.0125)


app = QApplication([sys.argv])
win = QMainWindow()

text_1 = QPlainTextEdit()
text_2 = QPlainTextEdit()
text_3 = QPlainTextEdit()

my_widget = QWidget()
my_widget.layout = QHBoxLayout()
my_widget.layout.addWidget(text_1)
my_widget.layout.addWidget(text_2)
my_widget.layout.addWidget(text_3)
my_widget.setLayout(my_widget.layout)

win.setCentralWidget(my_widget)

worker1 = Worker()
worker1.messageChanged.connect(text_1.appendPlainText)

worker2 = Worker()
worker2.messageChanged.connect(text_2.appendPlainText)

worker3 = Worker()
worker3.messageChanged.connect(text_3.appendPlainText)

worker1.start(run1)
worker2.start(run2)
worker3.start(run3)


win.show()

sys.exit(app.exec_())

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM