0

I have a GUI program built on PyQt5, which constantly receive messages. The GUI has a QLabel showing the number of messages received, and a QThread trying to receive messages and update counter in an infinite loop in the run(). Here is the code:

class ReceiveThread(QtCore.QThread):
    def __init__(self, parent, dialog, config):
        super(BufRecvThread, self).__init__(parent)
        #here dialog is the QDialog which contains the QLabel showing the message counter
        self.dialog=dialog             
        self.toStop=False

    def run(self):
        bufRecvCnt=0
        while not self.toStop:
            recv_buff=sock.recvMessage()
            bufRecvCnt=bufRecvCnt+1
            #self.dialog.lbBufRecvCnt is the QLabel showing the message counter
            self.dialog.lbBufRecvCnt.setText(str(bufRecvCnt))
            QApplication.processEvents() #this statement has no effect

However, most of the time, I find that the QLabel in the GUI does NOT render the counter properly, say, the ReceiveThread has received 10000 messages and block at sock.recvMessage(), the QLabel still shows "500" until I manually resize the GUI causing the GUI to rerender.

I tried the suggestions of this thread pyqt QtGraphicsView does not get updated within loop, and added QApplication.processEvents() into the loop, but still NOT work.

So, is it proper to directly update the GUI from another thread? PyQt - Modify GUI from another thread suggests to emit signals. As I'm not familiar with signal & slot, should I use a predefined signal of the QLabel, or May I define whatever signal as i need, as long as the corresponding slot will update the text of the QLabel with setText().

Community
  • 1
  • 1

1 Answers1

1

Only the main GUI thread can update the GUI. You should not directly interact with GUI objects outside the main thread. If you want to communicate with the main thread from worker threads, you need to use Signals and Slots

class Dialog(QtGui.QDialog):

    def __init__(self, parent):
        super(Dialog, self).__init__(parent)
        ...

        self.thread = ReceiveThread(self)
        self.thread.message_received.connect(self.handle_message)

    @QtCore.pyqtSlot(str)
    def handle_message(self, message):
        self.lbBufRecvCnt.setText(message)


class ReceiveThread(QtCore.QThread):

    message_received = QtCore.pyqtSignal(str)

    def __init__(self, parent, config):
        super(ReceiveThread, self).__init__(parent)           
        self.toStop = False

    def run(self):
        bufRecvCnt=0
        while not self.toStop:
            recv_buff = sock.recvMessage()
            bufRecvCnt = bufRecvCnt + 1
            self.message_received.emit(str(bufRecvCnt))
Brendan Abel
  • 35,343
  • 14
  • 88
  • 118