Why doesn't this code by using thread show button?

43 Views Asked by At

Actually I made some code for asking other question. But I met new issue. This Test Code make buttons in qthread. Buttons shows when I execute directly function run(). Unfortunately, if I execute start() for starting qthread instead of run(), there is no buttons.

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget
from PySide6.QtCore import QThread
from functools import partial


class TestButton(QPushButton):
    def __init__(self):
        super().__init__()
        self.index = 0

class BtnThread(QThread):
    def __init__(self, parent):
        super().__init__()
        self.parent = parent

    def run(self):
        for i in range(100):
            pbtn = TestButton()
            pbtn.index = i
            #pbtn.clicked.connect(lambda :self.slotfunc(i))
            pbtn.clicked.connect(partial(self.slotfunc, i))
            self.parent.vlayout.addWidget(pbtn)

    def slotfunc(self, i):
        print(str(i) + " pressed")

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.vlayout = QVBoxLayout()
        btnthread = BtnThread(self)
        #btnthread.start()   # <-- Run / Thread
        btnthread.run()
        self.basicWidget = QWidget()
        self.basicWidget.setLayout(self.vlayout)
        self.setCentralWidget(self.basicWidget)
        self.show()


app = QApplication()
window = MainWindow()
window.show()
app.exec()

Why call run() works well, and doensn't work to call start()?

1

There are 1 best solutions below

0
Alexander On

The way you have it written in your example now is essentially the same thing as if run was a method of MainWindow.

Like this:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.vlayout = QVBoxLayout()
        self.basicWidget = QWidget()
        self.run()
        self.basicWidget.setLayout(self.vlayout)
        self.setCentralWidget(self.basicWidget)
        self.show()

    def run(self):
        for i in range(100):
            pbtn = TestButton()
            pbtn.index = i
            pbtn.clicked.connect(lambda :self.slotfunc(i))
            pbtn.clicked.connect(partial(self.slotfunc, i))
            self.vlayout.addWidget(pbtn)

    def slotfunc(self, i):
        print(str(i) + " pressed")

The above example and your example behave identically.

The reason why it doesn't work when using the start method, as mentioned in the comments, widgets are not thread safe, widgets created in a separate thread cannot be shown or used by the main thread. You should see a bunch of warnings or errors in your terminal if you were to try.