【问题标题】:How can I access an outside attribute from within a Thread如何从线程内访问外部属性
【发布时间】:2018-04-16 05:16:24
【问题描述】:

我用 PyQt5 Designer 设计了一个 GUI。

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

问题是,当我尝试从 Ui_Form 访问变量“Button”时,会引发以下错误:AttributeError: 'Ui_Form' object has no attribute 'Button'。

我尝试将 self 作为tryMethod 线程的参数传递给线程,但它给了我“意外类型:(() -> 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_())

【问题讨论】:

    标签: python multithreading pyqt pyqt5 python-multithreading


    【解决方案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_())
    

    【讨论】:

      【解决方案2】:

      在调用 ui.setupUi(Form) 之前,您正在实例化 ui = Ui_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。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-09
        • 2014-08-10
        • 1970-01-01
        • 2021-11-27
        • 1970-01-01
        • 1970-01-01
        • 2011-03-13
        • 2019-03-29
        相关资源
        最近更新 更多