2012-03-25 2 views
3

Во-первых, я очень новичок в Python и Pyside. Чтобы немного улучшить самосовершенствование, я пытаюсь заставить QTimer выполнять каждую секунду в дочернем потоке моей программы PySide (на данный момент я просто хочу, чтобы она печатала «привет!» На терминал каждую секунду без замораживания главного окна).Таймер в дочерней теме в PySide

Я попытался преобразовать example I found on the Qt Wiki из C++ в Python/PySide, но так как я действительно не знаю C++, я предполагаю, что я его неправильно преобразовал, и именно поэтому он не работает должным образом.

На данный момент функция doWork() работает только один раз, а затем никогда больше. Что я делаю не так? Есть ли лучший способ выполнить функцию каждую секунду в PySide без замораживания главного окна?

Вот код (я удалил некоторые основной код окна, чтобы увеличить четкость):

from PySide import QtGui 
from PySide import QtCore 
from client_gui import Ui_MainWindow 

statsThread = QtCore.QThread() 

class MainWindow(QtGui.QMainWindow, Ui_MainWindow): 
    def __init__(self, parent=None): 
     super(MainWindow, self).__init__(parent) 
     #setup GUI 
     self.setupUi(self) 
     #start thread to update GUI 
     self.statsThread = updateStatsThread() 
     self.statsThread.start(QtCore.QThread.TimeCriticalPriority) 

class updateGuiWithStats(QtCore.QObject): 
    def Worker(self): 
     timer = QtCore.QTimer() 
     timer.timeout.connect(self.doWork()) 
     timer.start(1000) 

    def doWork(self): 
     print "hi!" 

class updateStatsThread (QtCore.QThread): 
    def run(self): 
     updater = updateGuiWithStats() 
     updater.Worker() 
     self.exec_() 

if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    frame = MainWindow() 
    frame.show() 
    sys.exit(app.exec_()) 

ответ

4

@ Masci уже указал на исправление, которое вам нужно для вашего timer.timeout.connect, но я вижу больше проблем, чем просто это.

Нет необходимости в создании глобальной QThread, который никогда не используется:

statsThread = QtCore.QThread() 

Ваш QTimer является сборщиком мусора сразу же потому, что его создали без родителей, и вы не сохраните его в своем классе. Вот почему даже после того, как вы исправить подключение таймера, он все еще не работает ... Попробуйте:

class UpdateGuiWithStats(QtCore.QObject): 

    def startWorker(self): 
     self.timer = QtCore.QTimer() 
     self.timer.timeout.connect(self.doWork) 
     self.timer.start(1000) 

Кроме того, используйте заглавной первую букву классов и верблюжьего для методов. Вы делаете смесь обоих способов.

Несколько примечаний на основе этой ссылки, которую вы предоставили, вашего примера и других комментариев здесь ... Вы можете использовать только QTimer в качестве решения, если ваш doWork() очень легкий и не будет блокировать ваш основной цикл событий с помощью куча данных хруст, спать и т. д. Если это так, то doWork() нужно будет перенести в QThread, как это делает ваш пример. Но в этот момент нет необходимости использовать цикл событий и QTimer в отдельном классе, который вызывает свою собственную работу. Все это можно объединить в один класс, например:

class UpdateStatsThread(QtCore.QThread): 

    def __init__(self, parent=None): 
     super(UpdateStatsThread, self).__init__(parent) 
     self._running = False 

    def run(self): 
     self._running = True 
     while self._running: 
      self.doWork() 
      self.msleep(1000) 

    def stop(self, wait=False): 
     self._running = False 
     if wait: 
      self.wait() 

    def doWork(self): 
     print "hi!" 
+0

Вы правы, полагая, что я хотел бы сделать больше в 'doWork()', чем просто вызывать 'print 'foo" или что-то в этом роде. Имея это в виду, я внедрил переработанный класс 'UpdateStatsThread()', который вы написали. Однако, когда я иду, чтобы выйти из потока, я получаю сообщение о том, что поток был уничтожен во время работы. Я предполагаю, что это из-за того, что я покинул поток, пока 'time.sleep (1)' все еще работает. Есть ли хороший способ выйти из потока и избежать этого сообщения? –

+0

Я полностью. Это определенно потому, что python уничтожает объект, прежде чем он действительно закончит. Я обновил свой ответ, чтобы добавить дополнительное ожидание к методу stop(). Я также обновил сон, чтобы использовать QThread.msleep() – jdi

+1

спасибо за хороший ответ! ;) – Kasramvd

1

в updateGuiWithStats класса Worker метод:

timer.timeout.connect(self.doWork()) 

должен быть

timer.timeout.connect(self.doWork) 

Вы подключаете сигнал тайм-аута до None (возвращаемое значение метода doWork()), и я думаю, поэтому он выполняется только один раз: doWork вызывается во время соединения и номоре. Когда вы подключаетесь, не забудьте подключить имя функции (в словах Pythonics, вызываемый объект), а не вызов функции.

Кстати, даже если вышеуказанное решение вашей проблемы, вы должны избегать использования потоков, поскольку QTimer уже делает по своему усмотрению. В docs you linked первый ответ на вопрос Когда я не должен использовать потоки? вопрос: Таймеры.

+0

QTimer не использует нить. – jdi

+0

Кроме того, решение использовать QTimer вместо QThread не является идеальным решением.Он работает только в том случае, если ваш 'doWork()' быстрый, чтобы он мог выполняться, а не блокировать цикл основного события. Если это тяжелый вызов, он все равно будет блокировать цикл событий каждый раз, когда он будет вызван. Таким образом, вам нужно будет переместить эту функциональность в поток. – jdi

+0

Согласитесь, но для нужд ОП я думаю, что потоки переполнены – Masci

Смежные вопросы