0

I am trying to messing up with something and I am not able to create a widget using threading. Could someone take a look at my test script and let me know why this does not work?

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import *

import threading
import time

class Main(QMainWindow):
    def __init__(self):
        super(Main, self).__init__()

        self._build_ui()
        
        main_thread = threading.Thread(target=self.thread_function)
        main_thread.start()

    def thread_function(self):
        i = 0
        while True:
            message = "Message number: {}".format(i)
            print (message)
            self.create_message_widget(message)
            i+=1
            time.sleep(1)

    def create_message_widget(self, message):
        print ("Testing 3")
        self.label = QLabel(self)
        self.label.setText(message)
        self.verticalLayout.addWidget(self.label)

    def _build_ui(self):
        self.setWindowTitle("Testing Window")
        
        # set the central widget and main layout
        self.centralWidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self)
        self.setCentralWidget(self.centralWidget)
        self.centralWidget.setLayout(self.verticalLayout)
        
        self.button = QPushButton("Run")
        self.button.clicked.connect(lambda: self.create_message_widget("Testing 1"))
        
        # adding widgets to the window
        self.verticalLayout.addWidget(self.button)
        
        self.create_message_widget("Testing 2")
        self.create_message_widget("Testing 2")
        self.create_message_widget("Testing 2")

        # show main window
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Main()
    sys.exit(app.exec()) 

The following script shows 3 functions where I did few Testing X. You can notice the Testing 2 are created fine. When we click the button we can see Testing 1 which is populated by button press.

In thread_function I call create_message_widget function and I thought that should automatically create widget every 1 sec but it does not do anything. Could someone explain why and if this is possible to make it works?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Bart
  • 11
  • 2
  • You cannot and should not create and modify the GUI directly from another thread, that is a basic rule of the QWidget – eyllanesc Mar 07 '21 at 20:34
  • the example which you provided is in C++ not in Python. I am not familiar with that language and would be able to translate this. So I would like to make my question to be open due to no answer for Python. Thanks – Bart Mar 07 '21 at 20:59
  • Have you read my comment? It can not be, in the duplicate post they explain why not. There is no need to use the codes. Why do you want to create widgets in another thread? Is it so expensive to create it on the main thread? If it isn't then just do it on the main thread – eyllanesc Mar 07 '21 at 21:02
  • I am creating chat using socket and my receive message is running in socket so when I receive a message I want to create a widget in main window – Bart Mar 07 '21 at 21:05
  • You realize that when introducing sockets the problem changes radically. You clearly have an XY problem, why do you think the solution is to create widgets in the other thread? The solution is to send a signal to the main thread with that information and then in the main thread you must create the widgets. – eyllanesc Mar 07 '21 at 21:08
  • See for example https://stackoverflow.com/a/55193404/6622587, https://stackoverflow.com/questions/50413628/using-qlineedit-settext-freezes-the-window-but-background-tasks-works-fine/50415394#50415394 and https://stackoverflow.com/questions/54731102/how-to-make-a-qml-objects-property-dynamically-updatable-through-socket-conne/54731324#54731324 OR better use QTcpSockets: https://stackoverflow.com/questions/55494422/python-qtcpsocket-and-qtcpserver-receiving-message/55768007#55768007 – eyllanesc Mar 07 '21 at 21:10
  • In your case 1) add `messageChanged = pyqtSignal(str)` before `def __init__(self):`, add `self.messageChanged.connect(self.create_message_widget)` after `self._build_ui()` and 3) change `self.create_message_widget(message)` of thread_function in `self.messageChanged.emit(message)` – eyllanesc Mar 07 '21 at 21:15
  • Yes, this works. and yes I should mention about socket because if someone read this will think why I do not want to do it in my main thread. Thank you so much... – Bart Mar 07 '21 at 21:24
  • Please read [ask] and review the [tour] – eyllanesc Mar 07 '21 at 21:27

0 Answers0