답변:
Nathan W가 지적한 것처럼 이 작업을 수행하는 방법은 멀티 스레딩을 사용하는 것이지만 QThread를 서브 클래 싱하는 것이 가장 좋은 방법은 아닙니다. 여기를 참조하십시오 : http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
를 만드는 방법에 대한 예제를 아래에서 참조한 다음 "올바른"방법으로 QObject
이동하십시오 QThread
. 이 예는 새로운 QGIS 2.0 API를 사용하여 벡터 레이어에있는 모든 기능의 총 면적을 계산합니다.
먼저, 우리를 위해 무거운 작업을 수행 할 "작업자"개체를 만듭니다.
class Worker(QtCore.QObject):
def __init__(self, layer, *args, **kwargs):
QtCore.QObject.__init__(self, *args, **kwargs)
self.layer = layer
self.total_area = 0.0
self.processed = 0
self.percentage = 0
self.abort = False
def run(self):
try:
self.status.emit('Task started!')
self.feature_count = self.layer.featureCount()
features = self.layer.getFeatures()
for feature in features:
if self.abort is True:
self.killed.emit()
break
geom = feature.geometry()
self.total_area += geom.area()
self.calculate_progress()
self.status.emit('Task finished!')
except:
import traceback
self.error.emit(traceback.format_exc())
self.finished.emit(False, self.total_area)
else:
self.finished.emit(True, self.total_area)
def calculate_progress(self):
self.processed = self.processed + 1
percentage_new = (self.processed * 100) / self.feature_count
if percentage_new > self.percentage:
self.percentage = percentage_new
self.progress.emit(self.percentage)
def kill(self):
self.abort = True
progress = QtCore.pyqtSignal(int)
status = QtCore.pyqtSignal(str)
error = QtCore.pyqtSignal(str)
killed = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal(bool, float)
워커를 사용하려면 벡터 레이어로 초기화하고 스레드로 옮기고 신호를 연결 한 다음 시작해야합니다. 여기에 무슨 일이 일어나고 있는지 이해하기 위해 위에 링크 된 블로그 를 보는 것이 가장 좋습니다 .
thread = QtCore.QThread()
worker = Worker(layer)
worker.moveToThread(thread)
thread.started.connect(worker.run)
worker.progress.connect(self.ui.progressBar)
worker.status.connect(iface.mainWindow().statusBar().showMessage)
worker.finished.connect(worker.deleteLater)
thread.finished.connect(thread.deleteLater)
worker.finished.connect(thread.quit)
thread.start()
이 예는 몇 가지 핵심 사항을 보여줍니다.
run()
작업자 의 메소드 내부의 모든 것은 try-except 문 안에 있습니다. 코드가 스레드 내에서 충돌하면 복구하기가 어렵습니다. 그것은 일반적으로에 연결하는 오류 신호를 통해 역 추적을 방출합니다 QgsMessageLog
.kill()
는 함수를 정상적으로 종료 할 수 있는 메서드를 구현합니다 . terminate()
방법을 시도하지 마십시오 QThread
-나쁜 일이 발생할 수 있습니다!플러그인 구조의 어딘가에 객체 thread
와 worker
객체를 추적하십시오 . 당신이하지 않으면 Qt는 화가납니다. 가장 쉬운 방법은 대화 상자를 만들 때 대화 상자에 저장하는 것입니다. 예 :
thread = self.thread = QtCore.QThread()
worker = self.worker = Worker(layer)
또는 Qt가 QThread의 소유권을 갖도록 할 수 있습니다.
thread = QtCore.QThread(self)
이 템플릿을 구성하기 위해 모든 튜토리얼을 파는 데 오랜 시간이 걸렸지 만 그 이후로 나는 모든 곳에서 재사용했습니다.
worker.progress.connect(self.ui.progressBar)
다른 것으로 변경 했지만 qgis-bin을 실행할 때마다 충돌합니다. 파이썬 코드 또는 qgis 디버깅 경험이 없습니다. 내가 얻는 것은 Access violation reading location 0x0000000000000008
무언가가 null 인 것처럼 보입니다. 처리 스크립트에서 이것을 사용할 수없는 일부 설정 코드가 있습니까?
이 작업을 수행하는 유일한 방법은 멀티 스레딩입니다.
class MyLongRunningStuff(QThread):
progressReport = pyqtSignal(str)
def __init__(self):
QThread.__init__(self)
def run(self):
# do your long runnning thing
self.progressReport.emit("I just did X")
thread = MyLongRunningStuff()
thread.progressReport.connect(self.updatetheuimethod)
thread.start()
약간의 추가 독서 http://joplaete.wordpress.com/2010/07/21/threading-with-pyqt4/
참고 어떤 사람들은 QThread에서 상속하는 것을 좋아하지 않으며, 이것이 "올바른"방법은 아니지만 분명히 효과가 있습니다 ....
이 질문은 비교적 오래되었으므로 업데이트 할 가치가 있습니다. QGIS 3에는 QgsTask.fromFunction (), QgsProcessingAlgRunnerTask () 및 QgsApplication.taskManager (). addTask ()에 대한 접근 방식이 있습니다.
예를 들어 PyQGIS3 에서 쓰레드 사용하기 BY MARCO BERNASOCCHI