PyQt5 не может добавить метку в область прокрутки из потока - PullRequest
0 голосов
/ 29 апреля 2020

Я использую поток для получения сообщений от сервера сокетов. Я получаю сообщение, пытаюсь добавить метку и получаю следующую ошибку: «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 в другой файл, чтобы он был немного чище, но он такой же, как вы написали.

1 Ответ

2 голосов
/ 29 апреля 2020

Чтобы понять проблему, вы должны иметь следующие четкие понятия:

  • Когда виджет добавляется в окно, тогда виджет является дочерним элементом окна.

  • Виджеты не являются поточно-ориентированными, поэтому к ним нельзя обращаться из другого потока.

  • Родительские виджеты обращаются к дочерним виджетам, поэтому дочерний элемент должен принадлежать тому же потоку в качестве родителя.

С учетом вышесказанного делается вывод, что виджеты не должны создаваться в другом потоке, но именно это вы и делаете, вызывая ошибку, решение в этих случаях заключается в отправке информация ("chatterMessage") для потока GUI через элемент потока -safe как сигналы, где должны создаваться виджеты.

Учитывая вышеизложенное, возможное решение - следующая реализация:

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, поэтому вы должны восстановить этот код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...