PyQt5不能从线程中添加标签到滚动区域。

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

我使用一个线程来接收来自socket服务器的消息。我收到消息并尝试添加一个标签,然后我得到了下一个错误。"QObject::setParent: 无法设置父线,新的父线在不同的线程中"

谁能给我解释一下为什么不能工作,我应该怎么做才能使这个工作?

def threaded_receiveMessage(chat, network):
    while True:
        try: 
            chatterMessage = network.recieveData()
            if chatterMessage:
                chat.addLabel(chatterMessage, selfThread = chat)
        except:
            print("Disconnected.")
            break



class RandomChattingMW(object):
    def RandomChattingSetup(self, MainWindow, username):
        # Connecting to network.
        self.username = username
        self.network = Network(username)
        start_new_thread(threaded_receiveMessage, (self, self.network))

    def addLabel(self, text):
            print("Adding a label")
            label = QtWidgets.QLabel(text)
            label.setStyleSheet("font: 11pt;")
            label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
            print(selfThread)
            self.lineEdit.setText("")
            self.layout.addWidget(label)

这只是代码的一部分,我不认为需要所有的东西。为了确保我清楚,我从network.recieveData()得到一个字符串,它是一个在另一个文件中运行socket.recv的函数,它确实调用了addLabel函数,它在这一行崩溃了。"self.lineEdit.setText("")"

完整的代码。

from PyQt5 import QtCore, QtGui, QtWidgets
import math
from NetWorkFolder.network import Network
from NetWorkFolder.NetworkManager import NetworkManager
from _thread import *

class RandomChattingMW(object):
    def RandomChattingSetup(self, MainWindow, username):
        # Connecting to network.
        self.username = username
        self.network = Network(username)


        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(540, 590)

        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")


        self.buttons()
        self.lineEdits()
        self.randomWidgetSetup()
        self.labels()
        self.lineLength = 73

        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

        #NetWork Manager
        self.manager = NetworkManager(self.network)
        self.manager.messageChanged.connect(self.addLabel)




    def buttons(self):
        # Send message button
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(0, 560, 61, 31))
        self.pushButton.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.pushButton.setAutoFillBackground(False)
        self.pushButton.setIcon(QtGui.QIcon('chatParts/sendPic.png'))
        self.pushButton.setIconSize(QtCore.QSize(50,31))
        self.pushButton.setText("")
        self.pushButton.setObjectName("pushButton")
        self.pushButton.clicked.connect(self.sendMessage)
        # Change Chat Button
        self.newChatButton = QtWidgets.QPushButton(self.centralwidget)
        self.newChatButton.setGeometry(QtCore.QRect(420, -1, 121,32))
        self.newChatButton.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
        self.newChatButton.setText("New Chat")
        self.newChatButton.setStyleSheet("font-size:11pt")
        self.newChatButton.setObjectName("newChatButton")
        self.newChatButton.clicked.connect(self.newChatConnection)


    def lineEdits(self):
        # Write message to chat.
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(60, 560, 480, 30))
        self.lineEdit.setObjectName("lineEdit")

    def labels(self):
        # My Username
        self.usernameLabel = QtWidgets.QLabel(self.centralwidget)
        self.usernameLabel.setEnabled(True)
        self.usernameLabel.setText("Username: " + self.username)
        self.usernameLabel.setStyleSheet("font-size:11pt")
        self.usernameLabel.move(0,0)       
        self.usernameLabel.setAlignment(QtCore.Qt.AlignLeft|
        QtCore.Qt.AlignVCenter)
        self.usernameLabel.setObjectName("usernameLabel")

        self.usernameLabel.resize(self.usernameLabel.sizeHint().width(), 30)
        # The person i am chatting with.
        self.chatUsernameLabel = QtWidgets.QLabel(self.centralwidget)
        self.chatUsernameLabel.setEnabled(True)
        self.chatUsernameLabel.setText("Chatter: " + "Name")
        self.chatUsernameLabel.setStyleSheet("font-size:11pt")
        self.chatUsernameLabel.move(self.usernameLabel.sizeHint().
        width()+15,0)
        self.chatUsernameLabel.setAlignment(
        QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
        self.chatUsernameLabel.setObjectName("chatUsernameLabel")
        self.chatUsernameLabel.resize(
        self.chatUsernameLabel.sizeHint().width(), 30)
    def randomWidgetSetup(self):
        # Chat. ScrollArea
        self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
        self.scrollArea.setGeometry(QtCore.QRect(0, 30, 540, 530))
        self.scrollArea.setFrameShadow(QtWidgets.QFrame.Plain)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        # Body that holds the widgets.
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        # Box that holds the widgets.
        self.layout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
        self.scrollAreaWidgetContents.setLayout(self.layout)
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.layout.addStretch(-1)
        self.layout.setSpacing(10)

    # Adds a label with the message sent to you/you sent to the scroll area.
    @QtCore.pyqtSlot(str)
    def addLabel(self, text):
            print("Adding a label")
            label = QtWidgets.QLabel(text)
            label.setStyleSheet("font: 11pt;")
            label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
            print(selfThread)
            self.lineEdit.clear()
            self.layout.addWidget(label)
    # Makes the message.
    def sendMessage(self):
        pass

    # Send the message to the network.
    def sendMessageNetwork(self, message):
        try:
            self.network.send(message)
        except:
            self.addLabel("All The User's have Left the chat!\nClick on new chat to find a new Group!")


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "RandomChatting"))

我把NetworkManager类放到了另一个文件里 所以会更简洁一些 但和你写的是一样的

python python-3.x sockets pyqt pyqt5
1个回答
2
投票

要理解这个问题,你必须有以下清晰的概念。

  • 当一个widget被添加到窗口中,那么这个widget就是窗口的一个子节点。

  • 小组件不是线程安全的,所以不应该从另一个线程访问它们。

  • 父部件访问子部件,所以子部件必须和父部件属于同一个线程。

通过以上的分析,我们可以得出结论,小组件不应该在另一个线程中创建,但这正是你所做的导致错误的原因,在这些情况下,解决方案是通过线程元素--安全的信号,将信息("chatterMessage")发送到GUI线程中,作为小组件应该被创建的信号。

考虑到上述情况,一个可能的解决方案是下面的实现。

class NetworkManager(QtCore.QObject):
    messageChanged = QtCore.pyqtSignal(str)

    def __init__(self, network, parent=None):
        super().__init__(parent)
        self._network = network

    @property
    def network(self):
        return self._network

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

    def _execute(self):
        while True:
            try:
                message = self.network.recieveData()
                if message:
                    self.messageChanged.emit(message)
            except:
                print("Disconnected.")
                break


class RandomChattingMW(object):
    def setupUi(self, MainWindow):
        # ...


class RandomChatting(QtWidgets.QMainWindow, RandomChattingMW):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

    @QtCore.pyqtSlot(str)
    def addLabel(self, text):
        print("Adding a label")
        label = QtWidgets.QLabel(text)
        label.setStyleSheet("font: 11pt;")
        label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.lineEdit.clear()
        self.layout.addWidget(label)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = RandomChatting()
    w.show()
    network = Network(username)
    manager = NetworkManager(network)
    manager.messageChanged.connect(w.addLabel)
    manager.start()
    sys.exit(app.exec_())

注意:我已经考虑到RandomChattingMW是用Qt Designer创建的,所以你必须恢复该代码。

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