Найти - Пользователи
Полная версия: PyQt4. Как прервать работу потока
Начало » GUI » PyQt4. Как прервать работу потока
1
voltron
Есть приложение на PyQt 4.4.3 + Python 2.5, выполняющее анализ неких данных, Т.к. анализ процедура длительная, решил вынести его в отдельный поток и предоставить юзеру возможность прервать выполнение этой операции. До этого с потоками практически не сталкивался, посмотрел доки, примеры и похожую по функционалу программу. Научился создавать поток, получать информацию о процессе работы, а вот сделать так, чтобы по нажатию на кнопку поток останавливал работу не получается. Вот небольшой пример
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class dlgTest( QDialog ):
def __init__( self, parent = None ):
QDialog.__init__( self, parent )

self.mainLayout = QVBoxLayout()

self.btnStart = QPushButton()
self.btnStart.setText("Start")
QObject.connect( self.btnStart, SIGNAL( "clicked()" ), self.startCalculation )

self.btnStop = QPushButton()
self.btnStop.setText("Stop")
QObject.connect( self.btnStop, SIGNAL( "clicked()" ), self.stopCalculation )

self.lblProgress = QLabel()
self.lblProgress.setText("Progress: 0")

self.mainLayout.addWidget(self.btnStart)
self.mainLayout.addWidget(self.btnStop)
self.mainLayout.addWidget(self.lblProgress)
self.setLayout(self.mainLayout)

self.setWindowTitle( self.tr( "Thread" ) )
self.resize( 120, 100 )

# запуск "анализа" в отдельном потоке
def startCalculation( self ):
self.threadCalc = workThread()
QObject.connect( self.threadCalc, SIGNAL( "runStatus(PyQt_PyObject)" ), self.runStatusFromThread )
self.threadCalc.start()
# остановка "анализа" по нажатию на кнопку
def stopCalculation( self ):
self.threadCalc.stop()
# для отображения процесса выполнения
def runStatusFromThread( self, status ):
self.lblProgress.setText( "Progress: " + str( status ) )

class workThread( QThread ):
def __init__( self, parent = None ):
QThread.__init__( self, parent )
self.running = False
self.counter = 0

def run( self ):
self.running = True
while True:
self.counter += 1
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), self.counter )
self.sleep(1)
# остановка потока
def stop( self ):
#self.counter = 0
self.running = False

if __name__ == "__main__":
app = QApplication( sys.argv )
frm = dlgTest()
frm.show()
sys.exit( app.exec_() )
При нажатии на кнопку Start поток запускается и начинает “анализ”, а вот нажатие на Stop ничего не дает. В чем моя ошибка? Может, что-то делаю не правильно? В примерах из комплекта PyQt ничего подходящего не нашел.

P.S.: Если ошибся топиком, прошу модераторов извинить и поправить.
PooH
Поток должен проверять, что self.running истинно, и завершаться в противном случае
class workThread( QThread ):
...

def run( self ):
self.running = True
while self.running:
self.counter += 1
self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), self.counter )
self.sleep(1)
voltron
Т.е. все действия, которые выполняет поток, нужно просто завернуть в цикл while self.running?
Спасибо! Буду пробовать.
gmorgunov
Поток можно завершить вот так, например:
# остановка потока
def stop( self ):
print 'stop'
self.terminate()
self.wait()
Тогда переменная self.running вообще-то и не нужна.:)
ZZZ
Это, вроде бы, и самый простой вариант, но я бы рекомендовал космотреть на микротридинг. Иногда правильный генератор будет лучше любой нити. А с Qt работает просто замечательно.

И вообще, так, к размышлению, рекомендую всегда держать в уме выражение вида:
res = (yield curr)
Я, когда открыл это, оно было для меня как откровение и с тех пор я слежу за “What's new in Python X.X?” Это первое…

И второе.
У меня сейчас довольно специфическая задача и я организовал интерфейс через handler. Для остановки вызывает своё исключение. Для управдение самим алготитмом можно править хандлер.
Чтобы было понятно, вот немного кода:
class StopException(Exception): pass

class Handler(object):
'Типа хендлер'
def __init__(self, processor):
self.processor = processor

def start(self, id):
self.id = id

def work_start(self):
'Начало части алгоритма'
pass
def work_pass(self, curr):
self.processor.setProgress(curr)
def work_error(self, exc):
self.processor.process_stop()
raise StopException, exc
def work_end(self):
'Конец части алгоритма'
pass

def end(self):
pass
def stop(self):
pass


def work(work_data, handler):
'Какая-то абстрактная работа'
id = get_id()
handler.start(id)

try:
self.work_start()
for i in range(100):
try:
# Пашем...
handler.work_pass(i)
except Error, exc:
# Ууупс
handler.work_error(exc)
self.work_end()

except StopException, exc:
handler.stop(exc)
return

handler.end()

# Используется примерно так.
handler = Handler(processor)
work(data, handler)
Но стоит сказать, что у меня на один алгоритм работет несколько разных нендлеров… Всё зависит от того, какое поведение от этого алгоритма мне надо получить в данной ситуации.

И в третьих… Через неделю будет год, как я написал это. Рекомендовал бы разобрать.

P.S. gmorgunov, любишь Pink Floyd? Никогда не понимал, почему “The Division Bell” никому не нравится, а меня плющит…
PooH
ZZZ
И вообще, так, к размышлению, рекомендую всегда держать в уме выражение вида:
res = (yield curr)
Что то я не понял смысл выражения :(
ZZZ
Никогда не понимал, почему “The Division Bell” никому не нравится, а меня плющит…
А там кроме заглавной песни почему-то ничего не запоминается. Хотя клип на нее хорош, хоооороош
ZZZ
PooH
Что то я не понял смысл выражения
5.2.8. Yield expressions
Да, PooH, yield, это не только ценный мех…

PooH
А там кроме заглавной песни почему-то ничего не запоминается. Хотя клип на нее хорош, хоооороош
Ну нет, не согласен… High Hopes вещь так вообще взрывает мозг! А Wearing The Inside Out разве плохо звучит? Suum сuique… Блин… А то я сейчас весь альбом перечислю… :-) Просто я люблю добротную профессиональную музыку и завидую этим дядям, потому что так я никогда не смогу играть, сколько бы я гитару не мучал…
PooH
ZZZ
5.2.8. Yield expressions
Да, PooH, yield, это не только ценный мех…
Аааа… это я просто выражения не понял. Ну генераторы я регулярно использую, особенно презенташка вдохновляет, где цепочка итераторов начинается на одной машине, а заканчивается уже на другой :)
ZZZ
PooH
А там кроме заглавной песни почему-то ничего не запоминается. Хотя клип на нее хорош, хоооороош
Ну нет, не согласен… High Hopes
Хм… оказывается именно ее я имел ввиду :) уж очень полотна на ветру запомнились
ZZZ
Просто я люблю добротную профессиональную музыку и завидую этим дядям, потому что так я никогда не смогу играть, сколько бы я гитару не мучал…
Я то барабаны терзал… Вообще последнее время Сантана доставляет :)
ZZZ
PooH
Аааа… это я просто выражения не понял.
Ну я к тому, что генератор может не только давать, но и получать объект, а также райзить исключения.

PooH
Вообще последнее время Сантана доставляет
Очень давно его не слышал… Но когда-то он мне очень нравился и уж его гитару ни с чем не спутаешь!
gmorgunov
Сейчас снова послушал. Раньше как-то больше впечатляло. Но Marooned и High Hopes… звучат по-прежнему.:)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB