Доступ к Python виджетам родительского класса в Qthread - PullRequest
0 голосов
/ 05 сентября 2018

Я хочу получить доступ к виджетам родительского класса в QThread классе

В этой строке выдается графический интерфейс пользователя "Example (). SetWindowTitle (" Window ")"

Как я могу это сделать?

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.myclass2 = myclass2()
        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 myclass2(QThread):
    def __init__(self, parent=None):
        super(myclass2, self).__init__(parent)

    def run(self):
        while True:
            time.sleep(.1)
            print(" in thread \n")
            Example().setWindowTitle("Window")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

1 Ответ

0 голосов
/ 05 сентября 2018

Вы должны понимать следующее выражение:

Example().setWindowTitle("Window")

эквивалентно:

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

То есть вы создаете другой объект-пример, отличный от ex = Example(), и этот объект создает другой объект myclass2, а этот другой объект myclass2 создает еще один пример, и явно создается бесконечный цикл.


Еще одна вещь, которая в будущем может вызвать у вас проблемы, это установить одно и то же имя для разных вещей, хотя в этом случае это не проблема, но в будущем это может вызвать проблемы, код, на который я ссылаюсь:

self.myclass2 = myclass2()

Например, рекомендуется, чтобы классы начинались с заглавных букв.


Другая ошибка, которая действительна только в Qt, заключается в том, что GUI нельзя создавать или обрабатывать в потоке, отличном от основного потока. Таким образом, вы не можете изменить заголовок непосредственно в другой ветке, но есть 2 способа:

1. QMetaObject::invokeMethod(...)

Но для этого мы должны передать GUI через свойство:

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. сигналы и слоты

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:

Вы не должны изменять графический интерфейс непосредственно из потока, а отправлять данные через сигнал:

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_())
...