【问题标题】:PYQT QTimer does not startPYQT QTimer 不启动
【发布时间】:2021-05-09 20:42:35
【问题描述】:

我正在将 PyQt 5 用于 GUI 应用程序,但我遇到了线程问题。

有一个关闭按钮,一旦按下它,QTimer 就会启动,然后它会在一个 while 循环中等待,该循环取决于 QTimer 处理程序中正在递增的变量的值。

问题是计时器没有启动。有趣的是,如果我对 while 循环进行注释,则计时器可以正常工作。

代码如下:

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QHBoxLayout

import sys
import time

class MyClass(QMainWindow):
    
    myTimer = None
    myCounter = 0

    
    
    def __init__(self):

        QMainWindow.__init__(self)
        
        myButton = QPushButton(text='Close')        
        myButton.clicked.connect(self.myButtonClicked)
        
        centralWidget = QWidget(self)          
        self.setCentralWidget(centralWidget)   

        ly = QHBoxLayout()     
        ly.addWidget(myButton)
        
        centralWidget.setLayout(ly) 
        
        self.myTimer = QTimer()
        self.myTimer .timeout.connect(self.__myTimerHandler)
        
        
 
    
    def myButtonClicked(self):

        self.myCounter= 0
           
        self.myTimer.start(1000)
           
        print('Loop Start')
           
        while self.myCounter < 10:
              self.__DoNothing()
           
        print('Loop END')   
        

    def __DoNothing(self):
         print('Nothing')
         #time.sleep(2)
    
    def __myTimerHandler(self):
         self.myCounter = self.myCounter + 1
         print('Counter:' + str(self.myCounter))
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWin = MyClass()
    mainWin.show()
    sys.exit( app.exec_() )
              
             

输出:

Loop Start
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing

正如我所解释的,使用此代码 QTImer(我的计时器)不会启动。但是,如果我注释 while 循环,QTimer 会正确启动,并且每秒都会调用一次处理程序。

注释掉 DoNothing 函数中的 time.sleep 行没有帮助。

我可以想象这是关于多线程和访问同一个变量的问题,但我不知道如何解决它。

【问题讨论】:

  • 在 Qt 主线程中永远不应发生阻塞函数或循环:您的计时器已启动,但由于 Qt 事件循环在 while 中被阻塞,因此无法处理它.只需检查__myTimerHandler 中的变量即可。
  • @musicamante 谢谢你的评论,现在我明白这是问题所在,但这样做的想法是等待调用处理程序的一定数量的重复,然后做其他事情,例如,在关闭窗口之前有一个从 20 到 0 的倒计时数。然后关闭窗口。
  • 我不明白问题出在哪里:你已经让计数器工作了,如果你想让它重复 20 次然后停止(或做其他事情),只需添加一个 if self.myCounter &gt;= 20: ...
  • 这就是我想说的,按照您建议的方式,我必须在 __myTimerHandler 中编写 if 条件行,但是我想在 myButtonClicked 函数中执行此操作。此实现的另一个好处是您可以将此计时器用作多个功能中的延迟。例如,如果你想在两行代码之间有一定的时间延迟。
  • @Majidkhalili 将QApplication.processEvents() 放入您的while 循环中,将time.sleep(1) 放入__DoNothing。这将允许在运行否则会阻塞事件循环的代码时处理计时器事件。

标签: python pyqt pyqt5 qthread qtimer


【解决方案1】:

正如@musicamante 在 cmets 中提到的“在主 Qt 线程中不应发生阻塞函数或循环”。而在问题中提供的代码中,线程实际上正在启动,但是由于阻塞循环,处理程序没有被调用的机会。

正如@ekhumoro 在 cmets 中提到的,解决方案是使用“QApplication.processEvents()”在等待循环中处理事件。并且还在“__DoNothing”函数中添加了一个休眠函数。

所以最终的解决方案如下:

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QHBoxLayout

import sys
import time

class MyClass(QMainWindow):
    
    myTimer = None
    myCounter = 0

    
    
    def __init__(self):

        QMainWindow.__init__(self)
        
        myButton = QPushButton(text='Close')        
        myButton.clicked.connect(self.myButtonClicked)
        
        centralWidget = QWidget(self)          
        self.setCentralWidget(centralWidget)   

        ly = QHBoxLayout()     
        ly.addWidget(myButton)
        
        centralWidget.setLayout(ly) 
        
        self.myTimer = QTimer()
        self.myTimer .timeout.connect(self.__myTimerHandler)
        
        
 
    
    def myButtonClicked(self):

        self.myCounter= 0
           
        self.myTimer.start(1000)
           
        print('Loop Start')
           
        while self.myCounter < 10:
              self.__DoNothing()
              QApplication.processEvents()
           
        print('Loop END')   
        

    def __DoNothing(self):
         print('Nothing')
         time.sleep(0.250)
    
    def __myTimerHandler(self):
         self.myCounter = self.myCounter + 1
         print('Counter:' + str(self.myCounter))
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWin = MyClass()
    mainWin.show()
    sys.exit( app.exec_() )

输出将完全符合预期,如下所示:

Loop Start
Nothing
Nothing
Nothing
Nothing
Counter:1
Nothing
Nothing
Nothing
Nothing
Counter:2
Nothing
Nothing
Nothing
Nothing
Counter:3
Nothing
Nothing
Nothing
Loop Start
Nothing
Nothing
Nothing
Nothing
Counter:1
Nothing
Nothing
Nothing
Nothing
Counter:2
Nothing
Nothing
Nothing
Nothing
Nothing
Counter:3
Nothing
Nothing
Nothing
Counter:4
Nothing
Nothing
Nothing
Nothing
Counter:5
Nothing
Nothing
Nothing
Nothing
Counter:6
Nothing
Nothing
Nothing
Nothing
Counter:7
Nothing
Nothing
Nothing
Nothing
Counter:8
Nothing
Nothing
Nothing
Nothing
Counter:9
Nothing
Nothing
Nothing
Nothing
Counter:10
Loop END
Loop END

显然两个计数器回调的时间差不一定相同。

【讨论】:

    猜你喜欢
    • 2012-05-16
    • 2015-08-13
    • 2022-08-05
    • 2014-09-05
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 1970-01-01
    • 2019-02-05
    相关资源
    最近更新 更多