[英]Python PyQt5 threading QObject: Cannot create children for a parent that is in a different thread
I'm using Python 3.7.6 with PyQt5 on my Windows 10 computer.我在 Windows 10 计算机上使用 Python 3.7.6 和 PyQt5。 I am trying to write a simple application that will run three different procedures at the same time showing the output in three separate text boxes in the same window.我正在尝试编写一个简单的应用程序,它将同时运行三个不同的过程,在同一窗口的三个单独的文本框中显示输出。 I have tried to create some simple base code to add to, but am having an issue using the threading module with PyQt5.我试图创建一些简单的基本代码来添加,但是在使用 PyQt5 的线程模块时遇到了问题。 Here is my code:这是我的代码:
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_())
When I run this code, it shows the desired output, but with multiple instances of the following error:当我运行此代码时,它显示了所需的输出,但出现以下错误的多个实例:
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)
I think I know why this is happening, but do not know how to fix it.我想我知道为什么会这样,但不知道如何解决。 I presume that I should use PyQt5's own QThread class, but cannot get my head around how to do it.我认为我应该使用 PyQt5 自己的 QThread 类,但无法理解如何去做。 Currently, I will just run my three separate text based Python applications with each showing its output in its own window, but I would prefer a single GUI based application with all three incorporated.目前,我将只运行我的三个独立的基于文本的 Python 应用程序,每个应用程序在自己的窗口中显示其输出,但我更喜欢一个基于 GUI 的应用程序,其中包含所有三个。
The problem has nothing to do with the use of QThread or not.问题与是否使用QThread无关。 The problem is that the GUI elements (for example the QWidget, QTextDocument, etc) are not thread-safe so you should not modify them or create them in a different thread than the main one.问题是 GUI 元素(例如 QWidget、QTextDocument 等)不是线程安全的,因此您不应修改它们或在与主线程不同的线程中创建它们。 To emphasize my initial comment in my solution I will not use QThread but I will continue using threading but I will send the information to the main thread through signals(what if they are thread-safe):为了在我的解决方案中强调我最初的评论,我不会使用 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.