2012-03-15 22 views
6

में मुख्य धागे से संकेत के लिए प्रतीक्षा करें मैंने अपनी स्क्रिप्ट में से एक को एक जीयूआई जोड़ने का फैसला किया। लिपि एक साधारण वेब स्क्रैपर है। मैंने एक कार्यकर्ता थ्रेड का उपयोग करने का निर्णय लिया और डेटा को पार्स करने में कुछ समय लग सकता है। मैंने पायसाइड का उपयोग करने का फैसला किया, लेकिन सामान्य रूप से क्यूटी का मेरा ज्ञान काफी सीमित है।पायसाइड एक कार्यकर्ता धागे

जैसा कि स्क्रिप्ट को कैप्चा में आने पर उपयोगकर्ता इनपुट की प्रतीक्षा करनी है, मैंने फैसला किया कि इसे QLineEdit आग returnPressed तक आग लगनी चाहिए और उसके बाद इसे कार्यकर्ता थ्रेड पर सामग्री भेज दें ताकि यह सत्यापन के लिए भेज सके। यह प्रेस कुंजी दबाए जाने के लिए व्यस्त-प्रतीक्षा से बेहतर होना चाहिए।

ऐसा लगता है कि सिग्नल की प्रतीक्षा सीधे आगे नहीं है क्योंकि मैंने सोचा था कि यह होगा और थोड़ी देर के लिए खोज करने के बाद मैं this के समान कई समाधानों में आया। थ्रेड में सिग्नलिंग और वर्कर थ्रेड में एक स्थानीय इवेंट लूप मेरे समाधान को थोड़ा और जटिल बना देता है।

कई घंटों तक इसके साथ टंकण करने के बाद भी यह काम नहीं करेगा।

क्या माना जाता है:

  • डेटा डाउनलोड करें जब तक कैप्चा में संदर्भित और प्रवेश एक पाश
  • डाउनलोड कैप्चा और उपयोगकर्ता के लिए यह प्रदर्शित करते हैं, शुरू QEventLoop को फोन करके बुला self.loop.exec_()
  • बाहर निकलें QEventLoop द्वारा loop.quit() एक वर्कर थ्रेड स्लॉट में self.line_edit.returnPressed.connect(self.worker.stop_waiting) कक्षा
  • वैधता अगर कैप्चा और लूप मान्य करें पर विफल रहता है, अन्यथा पिछले यूआरएल जो अब डाउनलोड करने योग्य होना चाहिए पुन: प्रयास करें, तो अगले यूआरएल

क्या होता है के साथ आगे बढ़ना:

  • ... ऊपर देखें ...

  • QEventLoop से बाहर निकलना काम नहीं करता है। self.loop.isRunning()False को exit() पर कॉल करने के बाद देता है। self.isRunningTrue देता है, क्योंकि इस तरह के थ्रेड अजीब परिस्थितियों में मरने लगते नहीं थे। अभी भी धागा self.loop.exec_() लाइन पर रोकता है। जैसे कि थ्रेड इवेंट लूप को निष्पादित कर रहा है, भले ही इवेंट लूप मुझे बताता है कि यह अब नहीं चल रहा है।

  • जीयूआई कार्यकर्ता धागे वर्ग के स्लॉट के रूप में प्रतिक्रिया करता है। मैं पाठ मधुमक्खी को कार्यकर्ता थ्रेड, ईवेंट लूप की स्थिति और धागे की स्थिति को देख सकता हूं, लेकिन ऊपर उल्लिखित रेखा निष्पादित होने के बाद कुछ भी नहीं।

कोड थोड़ा जटिल है, इस तरह के रूप में मैं महत्वहीन बाहर छोड़ने के छद्म कोड-अजगर-मिश्रण का एक सा जोड़ें:

class MainWindow(...): 
    # couldn't find a way to send the text with the returnPressed signal, so I 
    # added a helper signal, seems to work though. Doesn't work in the 
    # constructor, might be a PySide bug? 
    helper_signal = PySide.QtCore.Signal(str) 
    def __init__(self): 
     # ...setup... 
     self.worker = WorkerThread() 
     self.line_edit.returnPressed.connect(self.helper_slot) 
     self.helper_signal.connect(self.worker.stop_waiting) 

    @PySide.QtCore.Slot() 
    def helper_slot(self): 
     self.helper_signal.emit(self.line_edit.text()) 

class WorkerThread(PySide.QtCore.QThread): 
    wait_for_input = PySide.QtCore.QEventLoop() 

    def run(self): 
     # ...download stuff... 
     for url in list_of_stuff: 
      self.results.append(get(url)) 

    @PySide.QtCore.Slot(str) 
    def stop_waiting(self, text): 
     self.solution = text 
     # this definitely gets executed upon pressing return 
     self.wait_for_input.exit() 

    # a wrapper for requests.get to handle captcha 
    def get(self, *args, **kwargs): 
     result = requests.get(*args, **kwargs) 
     while result.history: # redirect means captcha 
      # ...parse and extract captcha... 
      # ...display captcha to user via not shown signals to main thread... 

      # wait until stop_waiting stops this event loop and as such the user 
      # has entered something as a solution 
      self.wait_for_input.exec_() 

      # ...this part never get's executed, unless I remove the event 
      # loop... 

      post = { # ...whatever data necessary plus solution... } 
      # send the solution 
      result = requests.post('http://foo.foo/captcha_url'), data=post) 
     # no captcha was there, return result 
     return result 

frame = MainWindow() 
frame.show() 
frame.worker.start() 
app.exec_() 

उत्तर

2

स्लॉट धागा कि QThread नियंत्रण में नहीं धागा जो QThread बनाई अंदर निष्पादित किया जाता है, और।

आप थ्रेड में कोई QObject ले जाएँ और संकेत करने के लिए अपने स्लॉट कनेक्ट करने की आवश्यकता है, और उस स्लॉट धागा अंदर निष्पादित किया जाएगा:

class SignalReceiver(QtCore.QObject): 
    def __init__(self): 
     self.eventLoop = QEventLoop(self)    

    @PySide.QtCore.Slot(str) 
    def stop_waiting(self, text):     
     self.text = text 
     eventLoop.exit() 

    def wait_for_input(self): 
     eventLoop.exec() 
     return self.text 

class MainWindow(...): 
    ... 
    def __init__(self): 
     ... 
     self.helper_signal.connect(self.worker.signalReceiver.stop_waiting) 

class WorkerThread(PySide.QtCore.QThread): 
    def __init__(self): 
     self.signalReceiver = SignalReceiver() 
     # After the following call the slots will be executed in the thread    
     self.signalReceiver.moveToThread(self)  

    def get(self, *args, **kwargs): 
     result = requests.get(*args, **kwargs) 
     while result.history: 
      ... 
      self.result = self.signalReceiver.wait_for_input() 
+0

दरअसल, कि मेरी समस्या हल। धन्यवाद। –

3

क्या आप QWaitCondition के लिए दिखता आदर्श का वर्णन कर रहे हैं।

सरल उदाहरण:

import sys 
from PySide import QtCore, QtGui 

waitCondition = QtCore.QWaitCondition() 
mutex = QtCore.QMutex() 

class Main(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(Main, self).__init__() 

     self.text = QtGui.QLineEdit() 
     self.text.returnPressed.connect(self.wakeup) 

     self.worker = Worker(self) 
     self.worker.start() 

     self.setCentralWidget(self.text) 

    def wakeup(self): 
     waitCondition.wakeAll() 

class Worker(QtCore.QThread): 
    def __init__(self, parent=None): 
     super(Worker, self).__init__(parent) 

    def run(self): 
     print "initial stuff" 

     mutex.lock() 
     waitCondition.wait(mutex) 
     mutex.unlock() 

     print "after returnPressed" 

if __name__=="__main__":  
    app = QtGui.QApplication(sys.argv) 
    m = Main() 
    m.show() 
    sys.exit(app.exec_()) 
संबंधित मुद्दे