जैसा कि नाथन डब्ल्यू बताते हैं, ऐसा करने का तरीका मल्टीथ्रेडिंग के साथ है, लेकिन क्यूथ्रेड को उप-वर्ग करना सबसे अच्छा अभ्यास नहीं है। यहाँ देखें: 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()
कार्यकर्ता की पद्धति के अंदर सब कुछ एक कोशिश को छोड़कर बयान के अंदर है। जब आपका कोड किसी थ्रेड के अंदर क्रैश होता है, तो इसे पुनर्प्राप्त करना मुश्किल है। यह त्रुटि सिग्नल के माध्यम से ट्रेसबैक का उत्सर्जन करता है, जिसे मैं आमतौर पर कनेक्ट करता हूं QgsMessageLog
।
- समाप्त संकेत जुड़ा हुआ विधि बताता है यदि प्रक्रिया सफलतापूर्वक पूरी हुई, साथ ही परिणाम भी।
- प्रगति संकेत केवल तभी कहा जाता है जब प्रतिशत पूर्ण रूप से बदल जाता है, बजाय हर सुविधा के लिए एक बार। यह कार्यकर्ता प्रक्रिया को धीमा करने वाली प्रगति पट्टी को अद्यतन करने के लिए बहुत अधिक कॉलों को रोकता है, जो कि कार्यकर्ता को दूसरे धागे में चलाने के पूरे बिंदु को पराजित करेगा: उपयोगकर्ता इंटरफ़ेस से गणना को अलग करने के लिए।
- कार्यकर्ता एक
kill()
विधि को लागू करता है, जो फ़ंक्शन को इनायत से समाप्त करने की अनुमति देता है। कोशिश न करें और terminate()
विधि का उपयोग करें QThread
- बुरी चीजें हो सकती हैं!
अपने प्लगइन संरचना में कहीं न कहीं अपने thread
और worker
वस्तुओं का ट्रैक रखना सुनिश्चित करें । यदि आप नहीं करते हैं तो क्यूटी को गुस्सा आता है। ऐसा करने का सबसे आसान तरीका है कि आप उन्हें बनाते समय अपने संवाद में संग्रहीत करें, जैसे:
thread = self.thread = QtCore.QThread()
worker = self.worker = Worker(layer)
या आप Qt को क्यूट्र्रेड के स्वामित्व को लेने दे सकते हैं:
thread = QtCore.QThread(self)
इस टेम्प्लेट को एक साथ रखने के लिए सभी ट्यूटोरियल्स को खोदने में मुझे एक लंबा समय लगा, लेकिन तब से मैं इसे सभी जगह पुनः उपयोग कर रहा हूं।