【问题标题】:Trying to update a textbox in pyqt while doing a calculation在进行计算时尝试更新 pyqt 中的文本框
【发布时间】:2016-10-24 17:30:18
【问题描述】:

我使用 pyqt 构建了一个小 gui,您可以在其中从 QComboBox 中选择 Key,然后使用 Value 进行通常需要 3 秒的数学计算,结果是一个短字符串。我正在文本框中的 gui 中更新计算出的短字符串。这是我的代码(我删除了数学计算代码,因为它不相关),到目前为止它正在工作:

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os 
dict1 = {"Key":Value, "Key2":Value2, "Key3":Value3} # Value are int's

class combodemo(QWidget):
  def __init__(self, parent = None):
    super(combodemo, self).__init__(parent)

    layout = QHBoxLayout()
    self.cb = QComboBox()
    self.cb.addItems([key for key in sorted(dict1.keys())])
    self.cb.currentIndexChanged.connect(self.selectionchange)

    layout.addWidget(self.cb)
    self.setLayout(layout)
    self.cb.textbox = QLineEdit(self)
    self.cb.textbox.move(100, 200)
    self.cb.textbox.resize(150,50)
    self.cb.textbox.setAlignment(Qt.AlignCenter)
    self.cb.textbox.setText("Initial Text")

  def selectionchange(self):
    #self.cb.textbox.setText("Calculating...") # THIS IS NOT WORKING
    self.cb.currentIndexChanged.connect(self.selectionchange)
    # MATH CALCULATION CODE GOES HERE[...]
    self.cb.textbox.setText("RESULT OF MATH CALCULATION")

def main():
  app = QApplication(sys.argv)
  ex = combodemo()
  ex.show()
  sys.exit(app.exec_())

if __name__ == '__main__':
  main()

现在程序在选择 Key 后冻结 3 秒(因为我正在做数学计算)。由于我的数学计算需要 3 秒,所以一旦选择了 QComboBox 中的 Key,我想将文本框更新为 "Calculating..."。因此,在执行数学计算时,我希望文本框显示"Calculating..."。一旦计算完成,它应该简单地重写文本框并显示数学结果。

在上面的代码中,我一开始就尝试在函数def selectionchange(self) 中实现它(未注释)。但它没有效果。我怎样才能做到这一点?

【问题讨论】:

    标签: python python-3.x pyqt pyqt4


    【解决方案1】:

    这就是大多数 GUI 的工作方式:GUI 运行循环(称为 mainloop 或 event loop),其中它以某种顺序进行许多思考:它获取鼠标/键盘事件,将它们发送到小部件,运行你的函数,执行其他东西,最后更新/重绘小部件。因此,当您更改函数中的文本时,它不会立即在屏幕上更新/重绘它。它会在您结束您的功能后稍后执行。因此,如果您运行长时间运行的函数,那么您不会立即看到更改的文本(并且窗口不会在鼠标和键盘上响应)。

    你可以使用

    app.processEvents()
    

    强制更新,但您仍然会遇到鼠标和键盘事件响应问题。您必须在第二个线程中运行计算。

    此代码适用于我,但并不理想。

    (第二个线程不应该直接更改 GUI - 它应该向第一个线程发送消息/信号。所以有更好的解决方案:Simplest way for PyQT Threading)

    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    import os,sys
    
    import time # to simulate long-running function
    import threading
    
    dict1 = {"Key":100, "Key2":200, "Key3":300} # Value are int's
    
    class ComboDemo(QWidget):
    
      def __init__(self, parent = None):
        super(ComboDemo, self).__init__(parent)
    
        layout = QHBoxLayout()
        self.cb = QComboBox()
        self.cb.addItems([key for key in sorted(dict1.keys())])
        self.cb.currentIndexChanged.connect(self.selectionchange)
    
        layout.addWidget(self.cb)
        self.setLayout(layout)
        self.cb.textbox = QLineEdit(self)
        self.cb.textbox.move(100, 200)
        self.cb.textbox.resize(150,50)
        self.cb.textbox.setAlignment(Qt.AlignCenter)
        self.cb.textbox.setText("Initial Text")
    
      def selectionchange(self):
        self.cb.textbox.setText("Calculating...")
    
        # get value from dict using selected key
        value = dict1[str(self.cb.currentText())]
    
        # run thread - args has to be tuple
        t = threading.Thread(target=self.calculation, args=(value, ) ) 
        t.start()
    
      def calculation(self, arg):
        # MATH CALCULATION CODE GOES HERE[...]
        time.sleep(3) # to simulate long-running function
        self.cb.textbox.setText("RESULT: " + str(arg))
    
    
    def main():
    
      app = QApplication(sys.argv)
      ex = ComboDemo()
      ex.show()
      sys.exit(app.exec_())
    
    if __name__ == '__main__':
      main()
    

    【讨论】:

      【解决方案2】:

      您可以使用进度条向用户显示正在进行的计算。这是一个例子(整个代码在http://zetcode.com/gui/pyqt4/widgets/:

      def initUI(self):      
      
          self.pbar = QtGui.QProgressBar(self)
          self.pbar.setGeometry(30, 40, 200, 25)
      
          self.btn = QtGui.QPushButton('Start', self)
          self.btn.move(40, 80)
          self.btn.clicked.connect(self.doAction)
      
          self.timer = QtCore.QBasicTimer()
          self.step = 0
      
      
      def timerEvent(self, e):
      
          if self.step >= 100:
      
              self.timer.stop()
              self.btn.setText('Finished')
              return
      
          self.step = self.step + 1
          self.pbar.setValue(self.step)
      
      def doAction(self):
      
          if self.timer.isActive():
              self.timer.stop()
              self.btn.setText('Calculating ...')
      
          else:
              self.timer.start(100, self)
              self.btn.setText('Stop')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-08-11
        • 1970-01-01
        • 1970-01-01
        • 2017-03-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-20
        相关资源
        最近更新 更多