Завершение темы в Python
-
03-07-2019 - |
Вопрос
У меня есть программа PyQt, в этой программе я запускаю новый поток для рисования сложного изображения. Я хочу знать, когда закончится поток, чтобы я мог напечатать изображение в форме.
Единственное препятствие, с которым я сталкиваюсь, заключается в том, что мне нужно вызывать метод рисования из потока GUI, поэтому я хочу, чтобы поток GUI что-то делал из потока рисования.
Я мог бы сделать это, используя один поток, но программа останавливается.
Раньше я делал это в C #, используя BackgroundWorker, у которого было событие для завершения.
Есть ли способ сделать это в Python? или я должен взломать основной цикл приложения PyQt и немного его изменить?
Решение
В примерах с PyQt-Py2.6-gpl-4.4.4-2 .exe , есть приложение Mandelbrot. В моей установке исходный код находится в C: \ Python26 \ Lib \ site-packages \ PyQt4 \ examples \ threads \ mandelbrot.pyw. Он использует поток для визуализации растрового изображения и сигнала (ищите код QtCore.SIGNAL), чтобы сообщить потоку графического интерфейса о времени рисования. Похоже, что вы хотите.
Другие советы
У меня была похожая проблема с одним из моих проектов, и я использовал сигналы, чтобы сообщить моему основному потоку графического интерфейса, когда отображать результаты от работника и обновлять индикатор выполнения.
Обратите внимание, что в Справочное руководство по PyQt . Не все из них применимы к Python (мне понадобилось время, чтобы понять это).
Вот примеры, которые вы хотите посмотреть для подключения сигнала Python к функции Python.
QtCore.QObject.connect(a, QtCore.SIGNAL("PySig"), pyFunction)
a.emit(QtCore.SIGNAL("pySig"), "Hello", "World")
Кроме того, не забудьте добавить __ pyqtSignals__ = (" PySig " ;,)
в свой рабочий класс.
Вот урезанная версия того, что я сделал:
class MyGui(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.worker = None
def makeWorker(self):
#create new thread
self.worker = Worker(work_to_do)
#connect thread to GUI function
QtCore.QObject.connect(self.worker, QtCore.SIGNAL('progressUpdated'), self.updateWorkerProgress)
QtCore.QObject.connect(self.worker, QtCore.SIGNAL('resultsReady'), self.updateResults)
#start thread
self.worker.start()
def updateResults(self):
results = self.worker.results
#display results in the GUI
def updateWorkerProgress(self, msg)
progress = self.worker.progress
#update progress bar and display msg in status bar
class Worker(QtCore.QThread):
__pyqtSignals__ = ( "resultsReady",
"progressUpdated" )
def __init__(self, work_queue):
self.progress = 0
self.results = []
self.work_queue = work_queue
QtCore.QThread.__init__(self, None)
def run(self):
#do whatever work
num_work_items = len(self.work_queue)
for i, work_item in enumerate(self.work_queue):
new_progress = int((float(i)/num_work_items)*100)
#emit signal only if progress has changed
if self.progress != new_progress:
self.progress = new_progress
self.emit(QtCore.SIGNAL("progressUpdated"), 'Working...')
#process work item and update results
result = processWorkItem(work_item)
self.results.append(result)
self.emit(QtCore.SIGNAL("resultsReady"))
Я полагаю, что ваш поток рисования может отправить событие в основной поток с помощью QApplication.postEvent. Вам просто нужно выбрать какой-то объект в качестве получателя события. Подробнее
Более подробно об ответе Джеффа: документация Qt по поддержка потока утверждает, что можно заставить обработчики событий (слоты на языке Qt) исполняться в потоке, которому " принадлежит " объект.
Таким образом, в вашем случае вы определяете слот printImage (QImage) в форме и сигнал doneDrawing (QImage) для всего, что создает изображение, и просто подключаете их с помощью очереди или автоматического подключения.