2013-04-14 4 views
5

मेरे पास एक QDialog है जो यूआई उत्तरदायी रखते हुए कुछ काम करने के लिए QThread बनाता है, यहां दी गई संरचना के आधार पर: How To Really, Truly Use QThreads; The Full ExplanationQDialog पर कथित रूप से QThread को समाप्त करना अस्वीकार()

QThread: Destroyed while thread is still running

मैं तो होना ही क्या चाहते हैं, उसमें पाश के लिए है: हालांकि, अगर (उपयोगकर्ता दबाने को रद्द करने या संवाद को बंद करने के कारण) को अस्वीकार() कहा जाता है, जबकि धागा अभी भी चल रहा है मैं कोई त्रुटि मिलती है कार्यकर्ता जल्दी तोड़ने के लिए, फिर पृष्ठभूमि में कुछ सफाई करें (उदाहरण के लिए कुछ कतार साफ़ करें, सिग्नल उत्सर्जित करें)। मैंने इसे अपने "रद्द" फ़ंक्शन के साथ करने में कामयाब रहा है, लेकिन मैं इसे अस्वीकार() (और इसे कई सारे तरीकों से बुलाया जा सकता है) के साथ अच्छी तरह से खेलने के लिए कैसे प्राप्त करूं? मैं नहीं चाहता कि संवाद सफाई के लिए इंतजार कर रहा है - इसे पृष्ठभूमि में चलना चाहिए, फिर शानदार तरीके से बाहर निकलना चाहिए।

नीचे नमूना कोड देखें जो समस्या प्रदर्शित करता है। किसी भी तरह की सहायता का स्वागत किया जाएगा।

#!/usr/bin/env python 

from PyQt4 import QtCore, QtGui 
import sys 
import time 

class Worker(QtCore.QObject): 
    def __init__(self): 
     QtCore.QObject.__init__(self) 

    def process(self): 
     # dummy worker process 
     for n in range(0, 10): 
      print 'process {}'.format(n) 
      time.sleep(0.5) 
     self.finished.emit() 

    finished = QtCore.pyqtSignal() 

class Dialog(QtGui.QDialog): 
    def __init__(self): 
     QtGui.QDialog.__init__(self) 
     self.init_ui() 

    def init_ui(self): 
     self.layout = QtGui.QVBoxLayout(self) 
     self.btn_run = QtGui.QPushButton('Run', self) 
     self.layout.addWidget(self.btn_run) 
     self.btn_cancel = QtGui.QPushButton('Cancel', self) 
     self.layout.addWidget(self.btn_cancel) 

     QtCore.QObject.connect(self.btn_run, QtCore.SIGNAL('clicked()'), self.run) 
     QtCore.QObject.connect(self.btn_cancel, QtCore.SIGNAL('clicked()'), self.reject) 

     self.show() 
     self.raise_() 

    def run(self): 
     # start the worker thread 
     self.thread = QtCore.QThread() 
     self.worker = Worker() 
     self.worker.moveToThread(self.thread) 
     QtCore.QObject.connect(self.thread, QtCore.SIGNAL('started()'), self.worker.process) 
     QtCore.QObject.connect(self.worker, QtCore.SIGNAL('finished()'), self.thread.quit) 
     QtCore.QObject.connect(self.worker, QtCore.SIGNAL('finished()'), self.worker.deleteLater) 
     QtCore.QObject.connect(self.thread, QtCore.SIGNAL('finished()'), self.thread.deleteLater) 
     self.thread.start() 

def main(): 
    app = QtGui.QApplication(sys.argv) 
    dlg = Dialog() 
    ret = dlg.exec_() 

if __name__ == '__main__': 
    main() 

उत्तर

8

आपका समस्या है: self.thread, अजगर से मुक्त हो जाता है, जबकि क्यूटी धागे अभी भी चल रहा है के बाद संवाद बंद कर दिया है या रद्द बटन दबाया जाता है।

ऐसी स्थिति से बचने के लिए, आप एक पैरेंट को उस धागे को निर्दिष्ट कर सकते हैं। उदाहरण के लिए,


    def run(self): 
     # start the worker thread 
     self.thread = QtCore.QThread(self) 
     self.worker = Worker() 
     self.worker.moveToThread(self.thread) 
     QtCore.QObject.connect(self.thread, QtCore.SIGNAL('started()'), self.worker.process) 
     QtCore.QObject.connect(self.worker, QtCore.SIGNAL('finished()'), self.thread.quit) 
     QtCore.QObject.connect(self.worker, QtCore.SIGNAL('finished()'), self.worker.deleteLater) 
     QtCore.QObject.connect(self.thread, QtCore.SIGNAL('finished()'), self.thread.deleteLater) 
     self.thread.start() 

तो यह क्यूटी बजाय PyQt के स्वामित्व में किया जाएगा और इसलिए जी सी द्वारा एकत्र नहीं किया जाएगा इससे पहले कि यह शान से क्यूटी से समाप्त हो जाता है। दरअसल, यह विधि सिर्फ क्यूटी को शिकायत नहीं करती है और समस्या को पूरी तरह से हल नहीं करती है।

सुगंधित रूप से धागे को समाप्त करने के लिए, सामान्य दृष्टिकोण कार्यकर्ता कार्य को रोकने के लिए ध्वज का उपयोग कर रहा है।
उदाहरण के लिए:

class Worker(QtCore.QObject): 
    def __init__(self): 
     QtCore.QObject.__init__(self) 

    def process(self): 
     # dummy worker process 
     self.flag = False 
     for n in range(0, 10): 
      if self.flag: 
       print 'stop' 
       break 
      print 'process {}'.format(n) 
      time.sleep(0.5) 
     self.finished.emit() 

    finished = QtCore.pyqtSignal() 

class Dialog(QtGui.QDialog): 
    def __init__(self, parent=None): 
     QtGui.QDialog.__init__(self, parent) 
     self.init_ui() 

    def init_ui(self): 
     self.layout = QtGui.QVBoxLayout(self) 
     self.btn_run = QtGui.QPushButton('Run', self) 
     self.layout.addWidget(self.btn_run) 
     self.btn_cancel = QtGui.QPushButton('Cancel', self) 
     self.layout.addWidget(self.btn_cancel) 

     QtCore.QObject.connect(self.btn_run, QtCore.SIGNAL('clicked()'), self.run) 
     QtCore.QObject.connect(self.btn_cancel, QtCore.SIGNAL('clicked()'), self.reject) 

     QtCore.QObject.connect(self, QtCore.SIGNAL('rejected()'), self.stop_worker) 

     self.show() 
     self.raise_() 

    def stop_worker(self): 
     print 'stop' 
     self.worker.flag = True 

    def run(self): 
     # start the worker thread 
     self.thread = QtCore.QThread(self) 
     self.worker = Worker() 
     self.worker.moveToThread(self.thread) 
     QtCore.QObject.connect(self.thread, QtCore.SIGNAL('started()'), self.worker.process) 
     QtCore.QObject.connect(self.worker, QtCore.SIGNAL('finished()'), self.thread.quit) 
     QtCore.QObject.connect(self.worker, QtCore.SIGNAL('finished()'), self.worker.deleteLater) 
     QtCore.QObject.connect(self.thread, QtCore.SIGNAL('finished()'), self.thread.deleteLater) 
     self.thread.start() 
+0

इस विधि का उपयोग यह बाहर निकलने से पहले साफ करने के लिए किसी भी धागे के लिए प्रतीक्षा करने के लिए मुख्य आवेदन प्राप्त करने के लिए संभव है? मैं कोड को एक बड़े एप्लिकेशन (क्यूजीआईएस) में प्लगइन के रूप में चला रहा हूं। – Snorfalorpagus

+0

@snorfalorpagus: मैंने अपनी पोस्ट अपडेट की। मुझे लगता है कि एक झंडा का उपयोग करना धागे को रोकने का सबसे सुरक्षित तरीका है। – nymk

संबंधित मुद्दे