GUI

2013-04-26 10 views
8

से QThread को कैसे रोकें यह पिछले एक पोस्ट के लिए एक अनुवर्ती प्रश्न है जिसे मैंने पहले पोस्ट किया था। समस्या यह है कि Qthread को उप-वर्गीकृत करने की अनुशंसित विधि का उपयोग करते समय GUI से QThread को रोकने के लिए कैसे रोकें (समाप्त करें | छोड़ें | बाहर निकलें), बल्कि एक QObject को सांस लेना और फिर इसे QThread पर ले जाना। एक कामकाजी उदाहरण के नीचे। मैं जीयूआई और क्यूथ्रेड शुरू कर सकता हूं और मैं बाद में जीयूआई अपडेट कर सकता हूं। हालांकि, मैं इसे रोक नहीं सकता। मैंने qthread के लिए कई विधियों की कोशिश की (छोड़ें(), बाहर निकलें(), और यहां तक ​​कि समाप्त()) का कोई फायदा नहीं हुआ। बहुत सराहना की मदद करें।GUI

import time, sys 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 

class SimulRunner(QObject): 
    'Object managing the simulation' 

    stepIncreased = pyqtSignal(int, name = 'stepIncreased') 
    def __init__(self): 
     super(SimulRunner, self).__init__() 
     self._step = 0 
     self._isRunning = True 
     self._maxSteps = 20 

    def longRunning(self): 
     while self._step < self._maxSteps and self._isRunning == True: 
      self._step += 1 
      self.stepIncreased.emit(self._step) 
      time.sleep(0.1) 

    def stop(self): 
     self._isRunning = False 

class SimulationUi(QDialog): 
    'PyQt interface' 

    def __init__(self): 
     super(SimulationUi, self).__init__() 

     self.goButton = QPushButton('Go') 
     self.stopButton = QPushButton('Stop') 
     self.currentStep = QSpinBox() 

     self.layout = QHBoxLayout() 
     self.layout.addWidget(self.goButton) 
     self.layout.addWidget(self.stopButton) 
     self.layout.addWidget(self.currentStep) 
     self.setLayout(self.layout) 

     self.simulRunner = SimulRunner() 
     self.simulThread = QThread() 
     self.simulRunner.moveToThread(self.simulThread) 
     self.simulRunner.stepIncreased.connect(self.currentStep.setValue) 


     self.stopButton.clicked.connect(simulThread.qui) # also tried exit() and terminate() 
     # also tried the following (didn't work) 
     # self.stopButton.clicked.connect(self.simulRunner.stop) 
     self.goButton.clicked.connect(self.simulThread.start) 
     self.simulThread.started.connect(self.simulRunner.longRunning) 
     self.simulRunner.stepIncreased.connect(self.current.step.setValue) 


if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    simul = SimulationUi() 
    simul.show() 
    sys.exit(app.exec_()) 
+0

[http://qt-project.org/doc/qt-4.8/qthread.html#quit] वास्तव में चाहिए करने के लिए जिस तरह से होना करने के लिए (मैं भी pyside उपयोग करने के लिए मेरे कोड बदल) यहां जाएं ... फिर से कोशिश करें, शायद फ़ंक्शन कॉल के आस-पास कुछ प्राथमिक डिबगिंग के साथ? – tmpearce

उत्तर

3

मुझे पता चला कि मेरी मूल प्रश्न एक में दो प्रश्न वास्तव में था: आदेश मुख्य एक से एक द्वितीय थ्रेड को रोकने के लिए, आप दो चीजों की जरूरत है:

यहाँ पूरा कोड है

  1. द्वितीय थ्रेड

  2. संदेश टी करने के लिए नीचे मुख्य थ्रेड से संवाद करने में सक्षम हो सकता है वह उचित संकेत धागा

मैं हल करने के लिए (2), लेकिन मैं समझ (1) है, जो मुझे अपने मूल समस्या का एक समाधान दिया हल करने के लिए कैसे समर्थ हुए को रोकने के लिए। इसके बजाय धागा रोकने की, मैं थ्रेड प्रसंस्करण (longRunning() विधि) बंद कर सकते हैं

समस्या यह है कि एक के लिए द्वितीयक थ्रेड केवल संकेतों का जवाब कर सकते हैं अगर यह अपने आप ही घटना पाश चलाता है। एक नियमित कथ्रेड (जो मेरा कोड इस्तेमाल होता है) नहीं करता है। यह उस प्रभाव के लिए QThread उपवर्ग के लिए, बहुत आसान है, हालांकि,:

class MyThread(QThread): 
    def run(self): 
     self.exec_() 

और मेरे बजाय कोड मूल self.simulThread = Qthread() में self.simulThread = MyThread() इस्तेमाल किया। यह सुनिश्चित करता है कि द्वितीयक थ्रेड एक ईवेंट लूप चलाता है। हालांकि, वह पर्याप्त नहीं था। longRunning() विधि को मुख्य थ्रेड से आने वाली घटना को वास्तव में संसाधित करने का मौका होना चाहिए। this SO answer की सहायता से मुझे पता चला किविधि में QApplication.processEvent() के सरल जोड़े ने माध्यमिक धागे को ऐसा मौका दिया। अब मैं प्रसंस्करण द्वितीयक थ्रेड में किए गए प्रसंस्करण को रोक सकता हूं, भले ही मुझे पता नहीं लगा कि थ्रेड को कैसे रोकें।

लपेटने के लिए। मेरे longRunning विधि अब इस तरह दिखता है:

def longRunning(self): 
    while self._step < self._maxSteps and self._isRunning == True: 
     self._step += 1 
     self.stepIncreased.emit(self._step) 
     time.sleep(0.1) 
     QApplication.processEvents() 

और मेरे जीयूआई धागा इन तीन लाइनों कि (ऊपर सूचीबद्ध QThread उपवर्ग के अलावा) काम कर दिया गया है:

self.simulThread = MyThread() 
    self.simulRunner.moveToThread(self.simulThread) 
    self.stopButton.clicked.connect(self.simulRunner.stop) 

टिप्पणियाँ स्वागत कर रहे हैं!

+0

मुझे इसके साथ बहुत सारे मुद्दे हैं, फिर मेरा स्वयं का समाधान बनाया गया है, इसे जांचें: https://github.com/u2ros/python-qt-multithreading – U2ros

6

मुझे इसकी बहुत पहले पता है लेकिन मैं बस एक ही समस्या पर ठोकर खाई।

मैं यह करने के लिए एक उचित तरीका भी खोज रहा हूं। अंत में यह आसान था। आवेदन से बाहर निकलने पर कार्य को रोकने की जरूरत है और थ्रेड को अपनी छोड़ने की विधि को कॉल करना बंद कर दिया जाना चाहिए। नीचे पर stop_thread विधि देखें। और आपको धागे को खत्म करने की प्रतीक्षा करनी होगी।अन्यथा आपको क्यू थ्रेड मिलेगा: थ्रेड अभी भी चल रहा है 'बाहर निकलने पर संदेश पर संदेश।

import time, sys 
from PySide.QtCore import * 
from PySide.QtGui import * 

class Worker(QObject): 
    'Object managing the simulation' 

    stepIncreased = Signal(int) 

    def __init__(self): 
     super(Worker, self).__init__() 
     self._step = 0 
     self._isRunning = True 
     self._maxSteps = 20 

    def task(self): 
     if not self._isRunning: 
      self._isRunning = True 
      self._step = 0 

     while self._step < self._maxSteps and self._isRunning == True: 
      self._step += 1 
      self.stepIncreased.emit(self._step) 
      time.sleep(0.1) 

     print "finished..." 

    def stop(self): 
     self._isRunning = False 


class SimulationUi(QDialog): 
    def __init__(self): 
     super(SimulationUi, self).__init__() 

     self.btnStart = QPushButton('Start') 
     self.btnStop = QPushButton('Stop') 
     self.currentStep = QSpinBox() 

     self.layout = QHBoxLayout() 
     self.layout.addWidget(self.btnStart) 
     self.layout.addWidget(self.btnStop) 
     self.layout.addWidget(self.currentStep) 
     self.setLayout(self.layout) 

     self.thread = QThread() 
     self.thread.start() 

     self.worker = Worker() 
     self.worker.moveToThread(self.thread) 
     self.worker.stepIncreased.connect(self.currentStep.setValue) 

     self.btnStop.clicked.connect(lambda: self.worker.stop()) 
     self.btnStart.clicked.connect(self.worker.task) 

     self.finished.connect(self.stop_thread) 

    def stop_thread(self): 
     self.worker.stop() 
     self.thread.quit() 
     self.thread.wait() 

if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    simul = SimulationUi() 
    simul.show() 
    sys.exit(app.exec_())