Saya telah mengembangkan beberapa alat pemrosesan batch sebagai plugin python untuk QGIS 1.8.
Saya menemukan bahwa ketika alat saya menjalankan GUI menjadi tidak responsif.
Kebijaksanaan umum adalah bahwa pekerjaan harus dilakukan pada utas pekerja, dengan informasi status / penyelesaian dikembalikan ke GUI sebagai sinyal.
Saya telah membaca dokumen tepi sungai , dan mempelajari sumber doGeometry.py (implementasi kerja dari ftools ).
Dengan menggunakan sumber-sumber ini saya telah mencoba membangun implementasi sederhana untuk menjelajahi fungsionalitas ini sebelum membuat perubahan pada basis kode yang sudah ada.
Struktur keseluruhan adalah entri dalam menu plugins, yang menghubungkan dialog dengan tombol start dan stop. Tombol-tombol mengontrol utas yang diperhitungkan hingga 100, mengirimkan sinyal kembali ke GUI untuk setiap nomor. GUI menerima setiap sinyal dan mengirimkan string yang berisi nomor log pesan, dan judul jendela.
Kode implementasi ini ada di sini:
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()
Sayangnya itu tidak tenang bekerja seperti yang saya harapkan:
- Judul jendela memperbarui "langsung" dengan penghitung tetapi jika saya mengklik pada dialog, itu tidak responsif.
- Log pesan tidak aktif hingga penghitung berakhir, kemudian menyajikan semua pesan sekaligus. Pesan-pesan ini ditandai dengan cap waktu oleh QgsMessageLog dan perangko waktu ini menunjukkan bahwa mereka diterima "langsung" dengan penghitung yaitu mereka tidak sedang antri oleh thread pekerja, atau dialog.
Urutan pesan dalam log (kutipan berikut) menunjukkan bahwa startButtonHandler menyelesaikan eksekusi sebelum utas pekerja mulai berfungsi yaitu utas berperilaku sebagai utas.
end: startButtonHandler Emit: starting work Emit: 0 ... Emit: 99 Emit: finshed work
Tampaknya utas pekerja tidak membagikan sumber daya apa pun dengan utas GUI. Ada beberapa baris komentar di akhir sumber di atas di mana saya mencoba memanggil msleep () dan yieldCurrentThread (), tetapi sepertinya tidak ada yang membantu.
Adakah yang punya pengalaman dengan ini dapat menemukan kesalahan saya? Saya berharap ini adalah kesalahan sederhana namun mendasar yang mudah untuk diperbaiki setelah diidentifikasi.