簡體   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