【问题标题】:PyQt5 Run function after displaying window显示窗口后的PyQt5运行功能
【发布时间】:2017-07-18 19:25:20
【问题描述】:

我想在 GUI 显示后调用一个函数。如果我在 init 中运行函数,它会阻止 gui 显示,直到它完成。

class MyApp(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        self.function() #waits for this to finish until gui displayed
    def function(self):
        self.guiBox.setValue(initData)
        #inits stuff, takes 5 seconds

该函数通过串口初始化一个设备...耗时几秒,获取gui属性并更新gui显示框。

【问题讨论】:

  • 你应该多说一下这个函数在做什么,你需要在主窗口里面吗(它是否引用了一些属性)?

标签: python python-3.x pyqt pyqt5


【解决方案1】:

耗时的任务被阻塞了,这违背了在 GUI 上工作的自然方式,一个选项是使用qApp.processEvents(),例如:

def function(self):
    self.guiBox.setValue(initData)
    code1
    QtWidgets.qApp.processEvents()
    code2
    QtWidgets.qApp.processEvents()
    ...

【讨论】:

  • 这与我需要的完全相反。我想让GUI先显示,然后运行函数。
  • 效果很好,谢谢!如果没有其他人提出更好的解决方案,我会在几天内接受作为答案。
  • 如果函数已知,它可以提供更好的解决方案。
  • 我认为更好的解决方案是独立于函数中发生的事情......我应该能够使用 function() 或 function2() 而不必显式处理 gui 事件每个。我的函数打开串行连接,发送命令,然后读取数据,并在 spinbox 中将数据显示到 GUI。
  • 我明白您在寻找什么,对我来说最好的解决方案是用最少的资源(内存和/或时间)执行任务的解决方案。 :P
【解决方案2】:

增加单发定时器1毫秒及后调用功能

  class MyApp(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
      QtWidgets.QMainWindow.__init__(self)
      Ui_MainWindow.__init__(self)
      self.setupUi(self)
      QTimer.singleShot(1,self.function) #waits for this to finish until gui displayed
    def function(self):
      self.guiBox.setValue(initData)
      #inits stuff, takes 5 seconds

【讨论】:

    【解决方案3】:

    我会推荐 QThreads,尤其是当您在“函数”中执行大量其他操作时。这个例子不是在 PyQt 中进行线程化的唯一方法,但认为一个能够在线程和主 gui 之间来回传递数据的例子是最好的。

    import os
    import sys
    from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
    from PyQt5.QtCore import QUrl, QEventLoop, QThread, QObject, pyqtSlot, pyqtSignal
    from PyQt5.QtWebEngineWidgets import QWebEngineView
    
    class time_consuming_function(QObject):
        def __init__(self, widget):
            super(time_consuming_function, self).__init__()
            self.widget = widget
            self.run_trigger.connect(self.run)
    
        run_trigger = pyqtSignal(int, int)
        @pyqtSlot(int, int)
        def run(self, int1, int2):
            print("In Time Consuming Function")
            for i in range(100000000):
                i*i
            print("Finished with Time Consuming Function")
            self.widget.someTrigger.emit([1, 2, 3])
    
    class WebPage(QWebEngineView):
        def __init__(self):
            QWebEngineView.__init__(self)
            self.load(QUrl("https://www.google.com"))
            self.loadFinished.connect(self._on_load_finished)
    
            self.someTrigger.connect(self.gui_response)
    
            self.thread = QThread()
            self.thread.start()
            self.consume = time_consuming_function(self)
            self.consume.moveToThread(self.thread)
            self.consume.run_trigger.emit(1,1)
    
        someTrigger = pyqtSignal(list)
    
        def _on_load_finished(self):
            print("Finished Loading")
    
        def gui_response(self, data):
            print("Responding to GUI: ", str(data))
    
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        web = WebPage()
        web.show()
        sys.exit(app.exec_())  
    

    【讨论】:

      【解决方案4】:

      我想说不使用线程和相关的最简单方法是验证显示窗口的最后一个事件是否已执行,然后调用您的方法。


      你会有类似的东西:

      import sys
      
      from PyQt5.QtCore import QEvent
      from PyQt5.QtWidgets import QApplication
      from PyQt5.QtWidgets import QMainWindow
      
      
      class MainWindow(QMainWindow):
      
          def __init__(self):
              super(MainWindow, self).__init__()
              self.setFixedSize(500, 500)
              self.move(300, 50)
      
          def print_1_bi(self):
              for i in range(10**9): print(i)
      
          def event(self, event):
              if event.type() == QEvent.InputMethodQuery:
                  self.print_1_bi()
              return super(MainWindow, self).event(event)
      
      
      if __name__ == "__main__":
          app = QApplication(sys.argv)
          mw = MainWindow()
          mw.show()
          sys.exit(app.exec_())
      

      注意: 请记住,即使 UI 已经显示,您的应用程序也会等待您的方法完成,如果这是一个问题,您将不得不使用这些人告诉您的过程在其他答案中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-04-02
        • 2016-07-17
        • 2021-12-27
        • 2020-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-19
        相关资源
        最近更新 更多