我使用一个线程来接收来自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类放到了另一个文件里 所以会更简洁一些 但和你写的是一样的
要理解这个问题,你必须有以下清晰的概念。
当一个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创建的,所以你必须恢复该代码。