Tôi đã phát triển một số công cụ xử lý hàng loạt như các plugin python cho QGIS 1.8.
Tôi đã thấy rằng trong khi các công cụ của tôi đang chạy GUI trở nên không phản hồi.
Sự khôn ngoan chung là công việc nên được thực hiện trên một luồng công nhân, với thông tin trạng thái / hoàn thành được chuyển trở lại GUI dưới dạng tín hiệu.
Tôi đã đọc qua các tài liệu ở bờ sông và nghiên cứu nguồn doGeometry.py (một triển khai làm việc từ ftools ).
Sử dụng các nguồn này, tôi đã cố gắng xây dựng một triển khai đơn giản để khám phá chức năng này trước khi thực hiện các thay đổi đối với cơ sở mã đã thiết lập.
Cấu trúc tổng thể là một mục trong menu bổ trợ, bao gồm một hộp thoại với các nút bắt đầu và dừng. Các nút điều khiển một luồng đếm đến 100, gửi tín hiệu trở lại GUI cho mỗi số. GUI nhận từng tín hiệu và gửi một chuỗi chứa số cả nhật ký tin nhắn và tiêu đề cửa sổ.
Mã của việc thực hiện này là ở đây:
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()
Thật không may, nó không hoạt động yên tĩnh như tôi hy vọng:
- Tiêu đề cửa sổ đang cập nhật "trực tiếp" với bộ đếm nhưng nếu tôi nhấp vào hộp thoại thì nó không phản hồi.
- Nhật ký tin nhắn không hoạt động cho đến khi bộ đếm kết thúc, sau đó trình bày tất cả các tin nhắn cùng một lúc. Các thông báo này được gắn thẻ có dấu thời gian bởi QssMessageLog và những dấu thời gian này cho biết chúng đã được nhận "trực tiếp" với bộ đếm, tức là chúng không được xếp hàng bởi luồng công nhân hoặc hộp thoại.
Thứ tự của các thông báo trong nhật ký (trích dẫn sau) chỉ ra rằng startButtonHandler hoàn thành việc thực thi trước khi các luồng xử lý của công nhân hoạt động tức là luồng xử lý như một luồng.
end: startButtonHandler Emit: starting work Emit: 0 ... Emit: 99 Emit: finshed work
Có vẻ như luồng công nhân không chia sẻ bất kỳ tài nguyên nào với luồng GUI. Có một vài dòng nhận xét ở cuối nguồn trên, nơi tôi đã thử gọi ms ngủ () và ieldCảnThread (), nhưng dường như không có ích.
Có ai có kinh nghiệm với điều này có thể phát hiện ra lỗi của tôi không? Tôi hy vọng đó là một lỗi đơn giản nhưng cơ bản, dễ sửa chữa một khi nó được xác định.