繁体   English   中英

PyQt5 无法添加 label 以从线程滚动区域

[英]PyQt5 can't add a label to scroll area from thread

我使用线程从套接字服务器接收消息。 我收到消息并尝试添加 label 并收到下一个错误:“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() 得到一个字符串,它是一个 function,它在另一个文件中运行 socket.recv,它确实调用了 addLabel function,它在这一行崩溃:“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 class 放在另一个文件中,这样它会更干净一些,但它和你写的一样。

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

  • 当一个小部件被添加到 window 时,该小部件是 window 的子部件。

  • 小部件不是线程安全的,因此不应从另一个线程访问它们。

  • 父小部件访问子小部件,因此子小部件必须与父小部件属于同一线程。

综上所述,小部件不应在另一个线程中创建,但这正是您正在做的导致错误的原因,在这些情况下的解决方案是通过线程元素将信息(“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 创建的,因此您必须恢复该代码。

暂无
暂无

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

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