2011-08-27 91 views
1

我一直在爲此奮鬥一段時間。我會盡力解釋我想做什麼,也許你們可以幫助我。PYQT - 如何使用取消按鈕在我的GUI中取消循環?

所以可以說我有與它的地位標籤和 兩個循環GUI看起來像這樣:

for _a in range(3000): 
    self.changeLabel('_a= '+ str(_a)) 

for _b in range(5000): 
    self.changeLabel('_b=' + str(_b)) 

def changeLabel(self,_text): 
    self.ui.STATUS.setText(_text) <---ui is a GUI where label is placed. 
    APP.processEvents()    

我希望有一個標籤(STATUS)與一個結果更新被壓在開始後(DONE ),並且我想在按下STOP按鈕時取消循環。

如何使用線程,QEventloop或任何其他方式(如果存在)實現此目的。我幾乎是初學PyQT,所以如果有人有任何想法 - 請分享。

謝謝。

回答

1

實現此目的的最簡單方法是使用生成器和「空閒計時器」。

這個想法是使用yield關鍵字將您的循環變成一個生成器,以便您可以使用next()從外部觸發每次迭代。然後你使用Qt的低級定時器(startTimer(),killTimer()timerEvent())創建一個間隔爲0的定時器,每當沒有更多事件要處理時調用它,以運行下一個循環迭代。這讓您有機會在循環期間對GUI事件做出反應,例如處理停止按鈕clicked()信號。

class MyWidget(QWidget): # Or whatever kind of widget you are creating 

    def __init__(self, parent, **kwargs): 
     super(MyWidget, self).__init__(parent, **kwargs) 
     # ... Create your widgets, connect signals and slots, etc. 
     self._generator = None 
     self._timerId = None 

    def loopGenerator(self): 
     # Put the code of your loop here 
     for a in range(3000): 
      self.ui.STATUS.setText("a=" + a) 
      # No processEvents() needed, just "pause" the loop using yield 
      yield 

    def start(self): # Connect to Start-button clicked() 
     self.stop() # Stop any existing timer 
     self._generator = self.loopGenerator() # Start the loop 
     self._timerId = self.startTimer(0) # This is the idle timer 

    def stop(self): # Connect to Stop-button clicked() 
     if self._timerId is not None: 
      self.killTimer(self._timerId) 
     self._generator = None 
     self._timerId = None 

    def timerEvent(self, event): 
     # This is called every time the GUI is idle. 
     if self._generator is None: 
      return 
     try: 
      next(self._generator) # Run the next iteration 
     except StopIteration: 
      self.stop() # Iteration has finshed, kill the timer 
+0

1.使用間隔爲0的QTimer而不是低級的QObject定時器函數更容易嗎?來自「簡明英漢詞典」這將是很多事件的小處理。也許每個事件做10到100次迭代而不是一次? – Macke

+0

@Macke:我想你也可以使用* QTimer *。不過,看不出這會如何讓事情變得更容易。是的,你可以在'yield'之前做多次迭代,但是你必須調用'processEvents()'來更新它們之間的GUI。通過使用一次迭代,您不必擔心這一點。請注意,這只是一個「概念驗證」,OP的任務是根據他/她的需求調整它。 –

+0

線程呢?由於PYQT應該有自己的線程,是否可以在線程上完成? – zebov

1

費迪南德的回答是不錯的,因爲它避免了使用processEvents的(),以使自己的事件循環。不過,我認爲有一個更簡單的解決方案:爲什麼不在停止按鈕被按下時設置一個標誌,並且如果標誌已被設置,則退出循環?喜歡的東西:

def stopClicked(self): 
    self.stop = True 

for _a in range(3000): 
    self.changeLabel('_a= '+ str(_a))  
    if self.stop: 
     self.stop = False 
     break 

def changeLabel(self,_text): 
    self.ui.STATUS.setText(_text) <---ui is a GUI where label is placed. 
    APP.processEvents() 
-1

我想給我解決這個問題。

我有一個類似的問題,同時創建一個使用PyQt從傳感器獲取實時照片的循環。

我發現使用QTimer是我唯一的工作解決方案,嘗試了收益率和檢查self.stop是真

由於線程非常過時,我將使用另一個與此處發佈的非常相似的示例。

我們想用某種信號初始化一個計數器(在這種情況下是一個按鍵),然後我們想用另一個按鍵來停止它。

我們打算使用QTimer對象,在定時器發出的timeout()信號期間升級計數器。

class MyExample(QObject): 

    timer = QTimer() 
    cont = 0 

    def __init__(self): 

     super(QObject, self).__init__() 

     # !!! IMPORTANT PART !!! 
     # Here we connect the timeout of the timer to the count 
     # function! 
     self.timer.timeout.connect(self.cont) 

    def keyEvent(self, e): 

     # Here we connect the keystroke to the event 
     # on the object! 
     if e.key() == Qt.Key_B: 

      self.start() 

     elif e.key() == Qt.Key_S: 

      self.stop() 

    def start(self): 
     # Number of milliseconds the timer waits until the timeout 
     self.timer.start(1000) 

    def stop(self): 
     self.timer.stop() 

    def count(self): 
     # Increase the counter on timeout 
     self.cont = self.cont + 1 
     print self.cont 

這個工作,至少對我來說! 希望這有助於某人!

+0

這並沒有解決發佈的線程問題。 QTimer可能是您唯一的解決方案,但這並不能解決OP問題。這應該是一個評論。 – Prune

+0

對不起,我認爲這是解決問題的另一種方法,因爲它是我唯一的工作解決方案。 – Giacomo