sickysickybrah
sickysickybrah

Reputation: 17

PySide or PyQT: using signals and slots to update GUI QLabel during QThread process

I am running a long process with QThread. In this process I send a signal to a slot. I want that slot to update a QLabel with setText(). I have ensured that my QThread process is on a separate thread and my message_updater function is on Main thread.

setText() is updating the text of the label, but it is not showing on the GUI. What am I doing wrong?

main.py

import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from run_worker_thread import RunWorkerThread
from return_message_label import ReturnMessage

class MainWindow(QMainWindow):
    
    def __init__(self):
        super().__init__()        
        
        self.setWindowTitle("PaGWIS")
        self.setMinimumSize(800, 400)        
        layout = QVBoxLayout()
        
        widgets = [
            RunWorkerThread,
            ReturnMessage
        ]
        
        for w in widgets:
            layout.addWidget(w())
            
        widget = QWidget()
        widget.setLayout(layout)
        
        self.setCentralWidget(widget)
        
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

worker_thread.py

from PySide6.QtCore import QThread, Signal
import time
import threading

class WorkerThread(QThread):
    update_progress = Signal(str)
    
    def run(self):
        
        count = 0
        while count < 10000:            
            count += 1
            print(f'worker: {count}')
            self.update_progress.emit(f'{count}')
            print(f'worker thread: {threading.current_thread()}')
            time.sleep(1)

run_worker_thread.py

from PySide6.QtWidgets import QWidget, QHBoxLayout, QPushButton
from worker_thread import WorkerThread
from return_message_label import ReturnMessage

class RunWorkerThread(QWidget):
    
    def __init__(self):
        super(RunWorkerThread, self).__init__()
        
        self.rm = ReturnMessage()
        self.worker = WorkerThread()
        
        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(10, 10, 10, 10)
        self.layout.setSpacing(20)
        
        btn = QPushButton('Process Data')
        btn.clicked.connect(self.processData)
        self.layout.addWidget(btn)
        
        self.setLayout(self.layout)
        
    def processData(self):
        self.worker.start()
        self.worker.update_progress.connect(self.rm.message_updater)

return_message_label.py

from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
from PySide6.QtCore import Slot
import threading

class ReturnMessage(QWidget):
    
    def __init__(self):        
        super(ReturnMessage, self).__init__()

        self.initUI()

    def initUI(self):
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(10, 10, 10, 10)
        self.layout.setSpacing(10)
        
        self.label1 = QLabel("python")
        
        self.layout.addWidget(self.label1)
        
        self.setLayout(self.layout)
        
    @Slot(str)
    def message_updater(self, msg):
        
        print(f'return msg thread: {threading.current_thread()}')
        print(f'msg_updater: {msg}')
        self.label1.setText(f'{msg}')

I've attempted to update the GUI the problem with: repaint(), update(), QApplication.ProcessEvents(). none of these worked

Upvotes: 0

Views: 133

Answers (1)

sickysickybrah
sickysickybrah

Reputation: 17

Special thanks to @musicamante who led me in the write path. Below is the solution to the dilemma:

main.py:

import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QLabel, QPushButton
from PySide6.QtCore import Slot
from return_message_label import ReturnMessage
from worker_thread import WorkerThread

class MainWindow(QMainWindow):
    
    def __init__(self):
        super().__init__() 
        
        self.worker = WorkerThread()
        self.rm = ReturnMessage()
        
        self.setWindowTitle("Title")
        self.setMinimumSize(800, 400)        
        self.layout = QVBoxLayout()
        
        self.layout.setContentsMargins(10, 10, 10, 10)
        self.layout.setSpacing(20)
        
        self.btn = QPushButton('Process Data')
        self.btn.clicked.connect(self.processData)
        self.layout.addWidget(self.btn)
        
        self.layout.addWidget(self.rm)
            
        widget = QWidget()
        widget.setLayout(self.layout)
        
        self.setCentralWidget(widget)
        
    def processData(self):
        self.worker.start()
        self.worker.update_progress.connect(self.rm.message_updater)
        
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

worker_thread.py:

from PySide6.QtCore import QThread, Signal
import time
import threading

class WorkerThread(QThread):
    update_progress = Signal(str)
    
    def run(self):
        
        count = 0
        while count < 10000:            
            count += 1
            print(f'worker: {count}')
            self.update_progress.emit(f'{count}')
            print(f'worker thread: {threading.current_thread()}')
            time.sleep(1)

return_message_label.py:

from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
from PySide6.QtCore import Slot
import threading

class ReturnMessage(QWidget):
    
    def __init__(self):        
        super(ReturnMessage, self).__init__()

        self.initUI()

    def initUI(self):
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(10, 10, 10, 10)
        self.layout.setSpacing(10)
        
        self.label1 = QLabel("python")
        
        self.layout.addWidget(self.label1)
        
        self.setLayout(self.layout)
        
    @Slot(str)
    def message_updater(self, msg):
        
        print(f'return msg thread: {threading.current_thread()}')
        print(f'msg_updater: {msg}')
        self.label1.setText(f'{msg}')

Upvotes: 0

Related Questions