मैं QGIS 1.8 के लिए अजगर प्लगइन्स के रूप में कुछ बैच प्रोसेसिंग टूल विकसित कर रहा हूं।
मैंने पाया है कि जब मेरे उपकरण चल रहे हैं तो GUI गैर-प्रतिक्रियाशील हो गया है।
सामान्य ज्ञान यह है कि काम कार्यकर्ता थ्रेड पर किया जाना चाहिए, स्थिति / पूर्ण जानकारी के रूप में संकेतों के रूप में जीयूआई को वापस कर दिया।
मैं के माध्यम से पढ़ा है नदी किनारे गए दस्तावेज़, और doGeometry.py के स्रोत (से एक काम कार्यान्वयन का अध्ययन किया ftools )।
इन स्रोतों का उपयोग करके मैंने एक स्थापित कोड बेस में परिवर्तन करने से पहले इस कार्यक्षमता का पता लगाने के लिए एक सरल कार्यान्वयन बनाने की कोशिश की है।
समग्र संरचना प्लगइन्स मेनू में एक प्रविष्टि है, जो प्रारंभ और स्टॉप बटन के साथ एक संवाद को प्रसारित करती है। बटन एक थ्रेड को नियंत्रित करता है जो 100 तक गिना जाता है, प्रत्येक नंबर के लिए GUI को एक सिग्नल वापस भेज रहा है। जीयूआई प्रत्येक संकेत प्राप्त करता है और एक स्ट्रिंग भेजता है जिसमें नंबर दोनों संदेश लॉग, और विंडो शीर्षक होता है।
इस कार्यान्वयन का कोड यहाँ है:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qgis.core import *
class ThreadTest:
def __init__(self, iface):
self.iface = iface
def initGui(self):
self.action = QAction( u"ThreadTest", self.iface.mainWindow())
self.action.triggered.connect(self.run)
self.iface.addPluginToMenu(u"&ThreadTest", self.action)
def unload(self):
self.iface.removePluginMenu(u"&ThreadTest",self.action)
def run(self):
BusyDialog(self.iface.mainWindow())
class BusyDialog(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
self.parent = parent
self.setLayout(QVBoxLayout())
self.startButton = QPushButton("Start", self)
self.startButton.clicked.connect(self.startButtonHandler)
self.layout().addWidget(self.startButton)
self.stopButton=QPushButton("Stop", self)
self.stopButton.clicked.connect(self.stopButtonHandler)
self.layout().addWidget(self.stopButton)
self.show()
def startButtonHandler(self, toggle):
self.workerThread = WorkerThread(self.parent)
QObject.connect( self.workerThread, SIGNAL( "killThread(PyQt_PyObject)" ), \
self.killThread )
QObject.connect( self.workerThread, SIGNAL( "echoText(PyQt_PyObject)" ), \
self.setText)
self.workerThread.start(QThread.LowestPriority)
QgsMessageLog.logMessage("end: startButtonHandler")
def stopButtonHandler(self, toggle):
self.killThread()
def setText(self, text):
QgsMessageLog.logMessage(str(text))
self.setWindowTitle(text)
def killThread(self):
if self.workerThread.isRunning():
self.workerThread.exit(0)
class WorkerThread(QThread):
def __init__(self, parent):
QThread.__init__(self,parent)
def run(self):
self.emit( SIGNAL( "echoText(PyQt_PyObject)" ), "Emit: starting work" )
self.doLotsOfWork()
self.emit( SIGNAL( "echoText(PyQt_PyObject)" ), "Emit: finshed work" )
self.emit( SIGNAL( "killThread(PyQt_PyObject)"), "OK")
def doLotsOfWork(self):
count=0
while count < 100:
self.emit( SIGNAL( "echoText(PyQt_PyObject)" ), "Emit: " + str(count) )
count += 1
# if self.msleep(10):
# return
# QThread.yieldCurrentThread()
दुर्भाग्य से यह चुपचाप काम नहीं कर रहा है जैसा कि मुझे उम्मीद थी:
- खिड़की का शीर्षक काउंटर के साथ "लाइव" अपडेट कर रहा है लेकिन अगर मैं संवाद पर क्लिक करता हूं, तो यह गैर-उत्तरदायी है।
- काउंटर समाप्त होने तक संदेश लॉग निष्क्रिय है, फिर सभी संदेशों को एक बार में प्रस्तुत करता है। इन संदेशों को QgsMessageLog द्वारा एक टाइम स्टैम्प के साथ टैग किया गया है और इन समय टिकटों से संकेत मिलता है कि उन्हें काउंटर के साथ "लाइव" प्राप्त हुआ था यानी उन्हें कार्यकर्ता धागे या संवाद द्वारा पंक्तिबद्ध नहीं किया जा रहा है।
लॉग में संदेशों का क्रम (निम्न प्रकार) इंगित करता है कि स्टार्टबटनहैंडलर कार्यकर्ता थ्रेड कॉमन्स काम करने से पहले पूरा करता है अर्थात थ्रेड एक थ्रेड के रूप में व्यवहार करता है।
end: startButtonHandler Emit: starting work Emit: 0 ... Emit: 99 Emit: finshed work
ऐसा लगता है कि वर्कर थ्रेड किसी भी संसाधन को GUI थ्रेड के साथ साझा नहीं कर रहा है। उपरोक्त स्रोत के अंत में टिप्पणी की गई कुछ पंक्तियाँ हैं, जहाँ मैंने msleep () और यील्डक्रेन्थ्रेड () को कॉल करने की कोशिश की, लेकिन न तो कोई मदद मिली।
किसी को भी इस अनुभव के साथ किसी को भी मेरी त्रुटि हाजिर करने में सक्षम है? मैं उम्मीद कर रहा हूं कि यह एक सरल लेकिन मौलिक गलती है जिसे पहचानने के बाद इसे ठीक करना आसान है।