Python access widgets of parent class in Qthread

后端 未结 1 728
傲寒
傲寒 2021-01-25 09:32

I want to access the parent class widgets in the QThread class

This line gives hangs GUI \"Example().setWindowTitle(\"Window\")\"

How can I do that

相关标签:
1条回答
  • 2021-01-25 10:03

    You must understand the following expression:

    Example().setWindowTitle("Window")
    

    it is equivalent to:

    obj = Example()
    obj.setWindowTitle("Window")
    

    That is, you are creating another Example object other than ex = Example(), and that object is creating another myclass2 object, and that other myclass2 object is creating another Example, and an infinite loop is clearly being created.


    Another thing that in the future could cause you problems is to establish the same name for different things, although in this case it is not a problem but in future occasions it could bring you problems, the code to which I refer is:

    self.myclass2 = myclass2()
    

    For example, it is recommended that classes should start with capital letters.


    Another error that is valid only in Qt is that the GUI can not be created or manipulated in a thread other than the main thread. So you can not change the title directly in the other thread but there are 2 methods:

    1. QMetaObject::invokeMethod(...)

    But for this we must pass the GUI through a property:

    class Example(QWidget):
        def __init__(self):
            super().__init__()
            self.myclass2 = MyClass()
            self.myclass2.gui = self
            self.myclass2.start()
            self.initUI()
    
        def initUI(self):
            self.setGeometry(300, 300, 300, 220)
            self.setWindowTitle('Icon')
            self.setWindowIcon(QIcon('web.png'))
            self.show()
    
    
    class MyClass(QThread):
        def run(self):
            while True:
                time.sleep(.1)
                print(" in thread \n")
                QMetaObject.invokeMethod(self.gui, "setWindowTitle", Qt.QueuedConnection, Q_ARG(str, "Window"))
    

    2. signals & slots

    class Example(QWidget):
        def __init__(self):
            super().__init__()
            self.myclass2 = MyClass()
            self.myclass2.titleChanged.connect(self.setWindowTitle)
            self.myclass2.start()
            self.initUI()
    
        def initUI(self):
            self.setGeometry(300, 300, 300, 220)
            self.setWindowTitle('Icon')
            self.setWindowIcon(QIcon('web.png'))
            self.show()
    
    
    class MyClass(QThread):
        titleChanged = pyqtSignal(str)
    
        def run(self):
            while True:
                time.sleep(.1)
                print(" in thread \n")
                self.titleChanged.emit("Window")
    

    PLUS:

    You should not modify the GUI from the thread directly but send the data through a signal:

    import sys
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class Example(QtWidgets.QWidget):
        def __init__(self):
            super().__init__()
            lay = QtWidgets.QVBoxLayout(self)
            le = QtWidgets.QLineEdit()
            lay.addWidget(le)
            self.myclass2 = MyClass()
            self.myclass2.titleChanged.connect(self.setWindowTitle)
            self.myclass2.infoChanged.connect(le.setText) # <-- connect signal
            self.myclass2.start()
            self.initUI()
    
        def initUI(self):
            self.setGeometry(300, 300, 300, 220)
            self.setWindowTitle('Icon')
            self.setWindowIcon(QtGui.QIcon('web.png'))
            self.show()
    
    
    class MyClass(QtCore.QThread):
        titleChanged = QtCore.pyqtSignal(str)
        infoChanged = QtCore.pyqtSignal(str) # <-- create signal
    
        def run(self):
            counter = 0
            while True:
                QtCore.QThread.msleep(100)
                print(" in thread \n")
                self.titleChanged.emit("Window")
                self.infoChanged.emit("{}".format(counter)) # <-- emit signal
                counter += 1
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())
    
    0 讨论(0)
提交回复
热议问题