如何从Thread中访问外部属性

时间:2018-04-16 05:16:25

标签: python multithreading pyqt pyqt5 python-multithreading

我使用PyQt5 Designer设计了一个GUI。

我希望 tryingMethod 始终检查来自服务器的传入消息,因此我创建了一个线程,以便GUI和run方法可以相同地运行,这是有效的。

问题在于,当我尝试访问变量" Button"从Ui_Form中,它抛出以下错误:AttributeError:' Ui_Form'对象没有属性'按钮'。

我尝试将self作为参数传递给tryMethod线程,但是它给了我" Unexpected类型:(() - > None,Ui_Form)警告"

我尝试过创建几个不同的类,但我无法解决问题。任何帮助表示赞赏! :)

class Ui_Form(object):
    def __init__(self):
        t = threading.Thread(target=self.tryingMethod)
        t.start()




    def tryingMethod(self):
        self.Button.setText("TESTING")  ##This doesn't work.

        while True:
            message = self.clientSocket.receive()



    def setupUi(self, Form):
        //Code has been shortened
        self.Button.setFont(font)
        self.Button.setCursor(QtGui.QCursor(QtCore.Qt.ForbiddenCursor))
        self.Button.setObjectName("Button")



if __name__ == "__main__":
     app = QtWidgets.QApplication(sys.argv)
     Form = QtWidgets.QWidget()
     ui = Ui_Form()
     ui.setupUi(Form)
     Form.show()
     sys.exit(app.exec_())

2 个答案:

答案 0 :(得分:1)

Qt不允许从另一个线程直接更新GUI,可能的解决方案是使用信号,但为此我们需要一个继承QObject的类,另一方面不建议修改由Qt Designer生成的类,该类仅用于填充小部件因此您可以利用创建从小部件继承的类,并且因为它是一个小部件也继承自QObject,在该类中我们将创建一个信号,并将该信号连接到按钮的setText()方法。

class Ui_Form(object):
    def setupUi(self, Form):
        # Code has been shortened
        self.Button.setFont(font)
        self.Button.setCursor(QtGui.QCursor(QtCore.Qt.ForbiddenCursor))
        self.Button.setObjectName("Button")

class Form(QtWidgets.QWidget, Ui_Form):
    someSignal = QtCore.pyqtSignal(str)
    def __init__(self, *args, **kwargs):
        QtWidgets.QWidget.__init__(self, *args, **kwargs)
        self.setupUi(self)
        t = threading.Thread(target=self.tryingMethod)
        self.someSignal.connect(self.Button.setText)
        t.start()

    def tryingMethod(self):
        self.someSignal.emit("TESTING")  ##This doesn't work.
        while True:
            message = self.clientSocket.receive()


if __name__ == "__main__":
     app = QtWidgets.QApplication(sys.argv)
     w = Form()
     w.show()
     sys.exit(app.exec_())

答案 1 :(得分:0)

您在致电ui = Ui_Form()之前实例化ui.setupUi(Form)

ui = Ui_Form()接下来将调用__init__方法,然后开始创建并启动您的主题。这将(在最坏的情况下)尝试在按钮创建之前设置按钮,这可能是您获得错误的原因。

您需要在尝试使用之前创建按钮。一种选择是将线程创建移到__init__之外,如下所示:

class Ui_Form(object):
    def startThread(self):
        t = threading.Thread(target=self.tryingMethod)
        t.start()

    def tryingMethod(self):
        self.Button.setText("TESTING")  ##This doesn't work.
        while True:
            message = self.clientSocket.receive()

    def setupUi(self, Form):
        # Code has been shortened
        self.Button.setFont(font)
        self.Button.setCursor(QtGui.QCursor(QtCore.Qt.ForbiddenCursor))
        self.Button.setObjectName("Button")


if __name__ == "__main__":
     app = QtWidgets.QApplication(sys.argv)
     Form = QtWidgets.QWidget()
     ui = Ui_Form()
     ui.setupUi(Form)
     Form.show()

     # call after creation
     ui.startThread()

     sys.exit(app.exec_())

那就是说,你的代码还有其他一些错误,例如提到的eyllanesc。