Seperti yang ditunjukkan oleh Nathan W , cara untuk melakukan ini adalah dengan multithreading, tetapi mensubklasifikasikan QThread bukan praktik terbaik. Lihat di sini: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Lihat di bawah ini contoh cara membuat QObject
, lalu pindahkan ke QThread
(yaitu cara "benar" untuk melakukannya). Contoh ini menghitung luas total semua fitur dalam lapisan vektor (menggunakan QGIS 2.0 API baru!).
Pertama, kita membuat objek "pekerja" yang akan melakukan tugas berat untuk kita:
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)
Untuk menggunakan pekerja kita perlu menginisialisasi dengan lapisan vektor, pindahkan ke utas, hubungkan beberapa sinyal, lalu mulai itu. Mungkin yang terbaik untuk melihat blog yang ditautkan di atas untuk memahami apa yang terjadi di sini.
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()
Contoh ini menggambarkan beberapa poin utama:
- Segala sesuatu di dalam
run()
metode pekerja ada di dalam pernyataan coba-kecuali. Sulit untuk dipulihkan ketika kode Anda macet di dalam utas. Ini memancarkan traceback melalui sinyal kesalahan, yang biasanya saya sambungkan ke QgsMessageLog
.
- Sinyal yang sudah selesai memberitahu metode yang terhubung jika proses selesai dengan sukses, dan juga hasilnya.
- Sinyal progres hanya dipanggil ketika persentase selesai berubah, bukan satu kali untuk setiap fitur. Ini mencegah terlalu banyak panggilan untuk memperbarui bilah kemajuan memperlambat proses pekerja, yang akan mengalahkan seluruh titik menjalankan pekerja di utas lain: untuk memisahkan perhitungan dari antarmuka pengguna.
- Pekerja menerapkan
kill()
metode, yang memungkinkan fungsi untuk mengakhiri dengan anggun. Jangan mencoba dan menggunakan terminate()
metode ini QThread
- hal-hal buruk bisa terjadi!
Pastikan untuk melacak objek Anda thread
dan worker
di suatu tempat di struktur plugin Anda. Qt marah kalau kamu tidak. Cara termudah untuk melakukan ini adalah menyimpannya di dialog saat Anda membuatnya, misalnya:
thread = self.thread = QtCore.QThread()
worker = self.worker = Worker(layer)
Atau Anda dapat membiarkan Qt mengambil kepemilikan atas QThread:
thread = QtCore.QThread(self)
Butuh waktu lama untuk menggali semua tutorial untuk menyatukan templat ini, tetapi sejak itu saya telah menggunakannya kembali di semua tempat.
worker.progress.connect(self.ui.progressBar)
ke yang lain, tetapi setiap kali saya menjalankannya qgis-bin mogok. Saya tidak punya pengalaman men-debug kode python atau qgis. Semua yang saya dapatkan adalahAccess violation reading location 0x0000000000000008
jadi sepertinya ada sesuatu yang nol. Apakah ada beberapa kode penyiapan yang tidak dapat digunakan dalam skrip pemrosesan?Satu-satunya cara sejati Anda untuk melakukan ini adalah dengan multithreading.
Beberapa bacaan tambahan http://joplaete.wordpress.com/2010/07/21/threading-with-pyqt4/
Catatan Beberapa orang tidak suka mewarisi dari QThread, dan tampaknya ini bukan cara yang "benar" untuk melakukannya, tetapi itu berhasil ....
sumber
Karena pertanyaan ini relatif lama, ia layak diperbarui. Dengan QGIS 3 ada pendekatan dengan QgsTask.fromFunction (), QgsProcessingAlgRunnerTask () dan QgsApplication.taskManager (). AddTask ().
Lebih lanjut tentang hal itu misalnya di Menggunakan Thread di PyQGIS3 OLEH MARCO BERNASOCCHI
sumber