PYQT QTimer не запускается

#python #pyqt #pyqt5 #qthread #qtimer

#python #pyqt #pyqt5 #qthread #qtimer

Вопрос:

Я использую PyQt 5 для приложения с графическим интерфейсом, и у меня возникла проблема с потоками.

Существует кнопка закрытия, и как только она нажата, запускается 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 запускается правильно, и обработчик вызывается каждую секунду.

Комментирование строки time.sleep в функции DoNothing не помогает.

Я могу себе представить, что это что-то о многопоточности и доступе к одной и той же переменной, но я понятия не имею, как это решить.

Комментарии:

1. В основном потоке Qt не должно происходить никакой функции блокировки или цикла : ваш таймер запущен, но он не может быть обработан, поскольку цикл событий Qt заблокирован в while . Просто проверьте переменную в __myTimerHandler .

2. @musicamante Спасибо за комментарий, теперь я понимаю, что это проблема, но идея этого заключалась в том, чтобы дождаться определенного количества повторений вызова обработчика, а затем выполнить другие действия, например, перед закрытием окна выполнить обратный отсчет от 20 до 0. а затем закройте окноокно.

3. Я не понимаю, в чем проблема: у вас уже работает счетчик, если вы хотите, чтобы он повторялся 20 раз, а затем останавливался (или делал что-либо еще), просто добавьте if self.myCounter >= 20: ...

4. Я пытаюсь сказать, что в том виде, в котором вы предлагаете, я должен написать эту строку условия if в __myTimerHandler, однако я хотел бы сделать это в функции myButtonClicked . Еще одним преимуществом этой реализации является то, что вы можете использовать этот таймер в качестве задержки в нескольких функциях. Например, если вы хотите иметь определенную временную задержку между двумя строками кодов.

5. @Majidkhalili вставил QApplication.processEvents() ваш цикл while и time.sleep(1) вошел __DoNothing . Это позволит обрабатывать события таймера во время выполнения кода, который в противном случае блокировал бы цикл событий.

Ответ №1:

Как упоминалось в комментариях @musicamante, «В основном потоке Qt никогда не должно происходить никакой функции блокировки или цикла». И в коде, приведенном в вопросе, поток фактически запускается, но из-за цикла блокировки обработчик не получает возможности быть вызванным.

Как упоминалось в комментариях @ekhumoro, решение заключается в обработке событий в цикле ожидания с использованием «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
 

Очевидно, что разница во времени между двумя обратными вызовами счетчиков не обязательно одинакова.