2012-11-07 14 views
10

निम्न कोड का उपयोग करते समय मेरा एप्लिकेशन कुछ सेकंड के बाद स्टाल करता है। और स्टालों से मेरा मतलब है लटकता है। मुझे विंडोज़ से एक खिड़की मिलती है जो प्रतीक्षा या बल बंद करती है।पायथन QT प्रोग्रेसबार

मैं यह जोड़ सकता हूं कि यह तब होता है जब मैं प्रगति पट्टी विंडो के अंदर या जब मैं इसके बाहर क्लिक करता हूं तो यह फोकस खो देता है। अगर मैं उदाहरण शुरू करता हूं और कुछ भी स्पर्श नहीं करता हूं तो यह काम करता है।

from PyQt4 import QtCore 
from PyQt4 import QtGui 


class ProgressBar(QtGui.QWidget): 
    def __init__(self, parent=None, total=20): 
     super(ProgressBar, self).__init__(parent) 
     self.name_line = QtGui.QLineEdit() 

     self.progressbar = QtGui.QProgressBar() 
     self.progressbar.setMinimum(1) 
     self.progressbar.setMaximum(total) 

     main_layout = QtGui.QGridLayout() 
     main_layout.addWidget(self.progressbar, 0, 0) 

     self.setLayout(main_layout) 
     self.setWindowTitle("Progress") 

    def update_progressbar(self, val): 
     self.progressbar.setValue(val) 

इस का उपयोग करते हुए इतना की तरह:

app = QtGui.QApplication(sys.argv) 
bar = ProgressBar(total=101) 
bar.show() 

for i in range(2,100): 
    bar.update_progressbar(i) 
    time.sleep(1) 

किसी भी मदद के लिए धन्यवाद।

उत्तर

12

आपको लूप चलने के दौरान ईवेंट को संसाधित करने की अनुमति देने की आवश्यकता है ताकि एप्लिकेशन उत्तरदायी रहे।

और भी महत्वपूर्ण बात यह है कि लंबे समय तक चलने वाले कार्यों के लिए, आपको उपयोगकर्ता को शुरू होने के बाद लूप को रोकने का एक तरीका प्रदान करना होगा।

ऐसा करने का एक आसान तरीका एक टाइमर के साथ लूप शुरू करना है, और फिर लूप चल रहा है, जबकि समय-समय पर qApp.processEvents पर कॉल करें।

import sys, time 
from PyQt4 import QtGui, QtCore 

class ProgressBar(QtGui.QWidget): 
    def __init__(self, parent=None, total=20): 
     super(ProgressBar, self).__init__(parent) 
     self.progressbar = QtGui.QProgressBar() 
     self.progressbar.setMinimum(1) 
     self.progressbar.setMaximum(total) 
     self.button = QtGui.QPushButton('Start') 
     self.button.clicked.connect(self.handleButton) 
     main_layout = QtGui.QGridLayout() 
     main_layout.addWidget(self.button, 0, 0) 
     main_layout.addWidget(self.progressbar, 0, 1) 
     self.setLayout(main_layout) 
     self.setWindowTitle('Progress') 
     self._active = False 

    def handleButton(self): 
     if not self._active: 
      self._active = True 
      self.button.setText('Stop') 
      if self.progressbar.value() == self.progressbar.maximum(): 
       self.progressbar.reset() 
      QtCore.QTimer.singleShot(0, self.startLoop) 
     else: 
      self._active = False 

    def closeEvent(self, event): 
     self._active = False 

    def startLoop(self): 
     while True: 
      time.sleep(0.05) 
      value = self.progressbar.value() + 1 
      self.progressbar.setValue(value) 
      QtGui.qApp.processEvents() 
      if (not self._active or 
       value >= self.progressbar.maximum()): 
       break 
     self.button.setText('Start') 
     self._active = False 

app = QtGui.QApplication(sys.argv) 
bar = ProgressBar(total=101) 
bar.show() 
sys.exit(app.exec_()) 

अद्यतन

यह मानते हुए कि आप अजगर की सी कार्यान्वयन (यानी CPython) का उपयोग कर रहे हैं, इस मुद्दे का हल पूरी तरह से निर्भर:

यहाँ एक डेमो स्क्रिप्ट है कि है कार्य (ओं) की प्रकृति पर जो जीयूआई के साथ एक साथ चलाना है। अधिक मौलिक रूप से, यह सीपीथॉन द्वारा Global Interpreter Lock (GIL) होने के द्वारा निर्धारित किया जाता है।

मैं सीपीथन के जीआईएल के किसी भी स्पष्टीकरण का प्रयास नहीं करने जा रहा हूं: इसके बजाय, मैं बस डेव बेज़ले द्वारा इस उत्कृष्ट PyCon video को देखने की सलाह दूंगा, और इसे छोड़ दूंगा।


आम तौर पर, जब एक पृष्ठभूमि कार्य के साथ समवर्ती एक जीयूआई भागने की कोशिश कर, पहले सवाल पूछने के लिए है: कार्य आईओ बाध्य है, या सीपीयू बाध्य?

यदि यह आईओ-बाध्य है (उदाहरण के लिए स्थानीय फाइल सिस्टम, इंटरनेट से डाउनलोड करना आदि), तो समाधान आमतौर पर काफी सरल होता है, क्योंकि सीपीथन हमेशा आई/ओ संचालन के लिए जीआईएल जारी करता है। पृष्ठभूमि कार्य को आसानी से asynchronously किया जा सकता है, या worker thread द्वारा किया जा सकता है, और जीयूआई उत्तरदायी रखने के लिए विशेष जरूरतों को पूरा करने की आवश्यकता नहीं है।

मुख्य कठिनाइयों सीपीयू-बाध्य कार्यों के साथ होती है, जब पूछने के लिए दूसरा प्रश्न होता है: क्या कार्य छोटे चरणों की श्रृंखला में विभाजित हो सकता है?

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

लेकिन यदि कार्य छोटे चरणों में विभाजित नहीं किया जा सकता है, तो सामान्य थ्रेडिंग-प्रकार समाधानों में से कोई भी काम नहीं करेगा। जीयूआई तब तक स्थिर हो जाएगा जब तक कार्य पूरा नहीं हो जाता है, भले ही थ्रेड का उपयोग किया जाता है या नहीं। अर्थात multiprocessing मॉड्यूल का इस्तेमाल करते हैं -

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

+0

यदि मैं इसे जीयूआई विंडो स्टालों के साथ-साथ "प्रतिक्रिया नहीं दे रहा हूं, बंद करें" त्रुटि के साथ चलाता हूं। हालांकि अगर मैं अपने सभी कार्यों को समाप्त होने तक प्रतीक्षा करता हूं तो सामान्य आवेदन जारी रहता है। – Tuim

+1

@Tuim। मेरी लिपि आपके प्रश्न में कोड के आधार पर सिर्फ एक साधारण डेमो है। यह एक सार्वभौमिक समाधान नहीं है जो सभी स्थितियों में काम करने जा रहा है। आप जो भी करने की कोशिश कर रहे हैं उसके उचित स्पष्टीकरण के साथ आपको अपने प्रश्न को अपडेट करने की आवश्यकता है। आप इन "कार्यों" का क्या उल्लेख करते हैं? क्या वे सीपीयू-बाध्य हैं, या आईओ-बाध्य हैं? क्या वह एप्लिकेशन है जो आपके द्वारा लिखे गए कार्यों को पूरा करता है, और इसलिए संशोधित कर सकता है? इसमें किस भाषा में लिखा गया है? आदि, – ekhumoro

+0

ये कार्य अधिष्ठापन हैं जैसे ज़िप फ़ाइलों को अनपॅक करना, एमएसआई/डीब पैकेजों को इस तरह की चीजों को स्थापित करना। लेकिन यह मामले के लिए बहुत प्रासंगिक नहीं है। आवेदन पायथन में भी लिखा गया है और पूरी तरह से अनुकूलन योग्य है। इसके अलावा मुझे कॉपी-पेस्ट-सक्षम उत्तर की उम्मीद नहीं है! मैं सही दिशा में एक संकेत की उम्मीद कर रहा हूं और जो आपने मेरे लिए सही दिशा प्रतीत नहीं किया है, मैंने कोशिश की है। कोई अपराध नहीं। – Tuim

0

जब आप गुई प्रोग्रामिंग करते हैं तो आपको बहु-थ्रेडिंग के कुछ रूपों का उपयोग करने की आवश्यकता होती है, आपके पास एक कार्यकर्ता धागा होता है और एक जो गुई को अपडेट करता है और माउस और कीबोर्ड ईवेंट का जवाब देता है। ऐसा करने के कई तरीके हैं। मेरा सुझाव है कि आप इस QProgressBar tutorial पर एक नज़र डालें, जिसमें QProgressBar का उपयोग करने का उत्कृष्ट कार्य उदाहरण है।

ट्यूटोरियल में वे QBasicTimer का उपयोग कर रहे हैं जो मुख्य धागे पर नियंत्रण उत्पन्न करने का तरीका है ताकि यह जीयूआई घटनाओं का जवाब दे सके। अपने कोड में time.sleep का उपयोग करके आप एक सेकंड के लिए अवरुद्ध कर रहे हैं जो एकमात्र थ्रेड चल रहा है।

+0

मुझे इसके बारे में पता है। लेकिन वे उदाहरण में हैं क्योंकि वे थ्रेडिंग का और अधिक उपयोग नहीं कर रहे हैं। – Tuim

+1

@Tuim: हाँ वे हैं, 'time.sleep()' का उपयोग न करें। – Junuxx

+0

@Tuim मैंने आगे यह बताने के लिए उत्तर अपडेट किया कि आपका कोड और ट्यूटोरियल एक ही चीज़ क्यों नहीं कर रहे हैं। –