2012-11-07 7 views
10

다음 코드를 사용하면 응용 프로그램이 몇 초 후에 멈 춥니 다. 그리고 마구간에 나는 의미한다. 나는 창문에서 기다리거나 강제로 닫는 창을 얻는다.Python QT ProgressBar

진도 표시 줄 창 안쪽을 클릭하거나 포커스 바깥 쪽을 클릭하여 포커스를 잃을 때만이 작업이 수행된다는 것을 추가 할 수도 있습니다. 예제를 시작하고 아무 것도 건드리지 않으면 마치 예제처럼 작동합니다. 이 사용

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_()) 

UPDATE

당신은 파이썬의 C 구현 (즉, CPython과)를 사용하는 것을 가정을,이 문제에 대한 해결책이 달려 : 여기

는 것을 수행하는 데모 스크립트입니다은 GUI와 동시에 실행해야하는 작업의 성격에 대해 설명합니다. 더 근본적으로 CPython은 Global Interpreter Lock (GIL)을 가지고 있습니다.

CPython의 GIL에 대한 설명을하지 않으려 고합니다. 대신 Dave Beazley가이 우수한 PyCon video을 보면서 권장합니다. 작업이 IO 바인딩, 또는 CPU-바인딩 : 백그라운드 작업과 동시에 GUI를 실행하려고 할 때


는 일반적으로 첫 번째 질문은이 물어?

CPython이 I/O 작업을 위해 항상 GIL을 릴리스하기 때문에 IO 바인딩 (예 : 로컬 파일 시스템 액세스, 인터넷에서 다운로드)의 경우 솔루션은 일반적으로 매우 직관적입니다. 백그라운드 작업은 간단히 asynchronously으로 수행하거나 worker thread으로 수행 할 수 있으며 GUI 응답 성을 유지하기 위해 수행해야 할 특별한 작업은 없습니다.

두 번째 질문이있을 때 CPU 바인딩 작업에서 가장 큰 어려움이 있습니다. 작업을 일련의 작은 단계로 나눌 수 있습니까?

가능한 경우 해결 방법은 주기적으로 GUI 스레드에 요청을 보내 현재 대기중인 스택을 처리하는 것입니다. 위의 데모 스크립트는이 기술의 원시 예제입니다. 일반적으로 작업은 별도의 작업자 스레드에서 수행되며 작업의 각 단계가 완료되면 GUI 업데이트 신호를 내 보냅니다. (참고 : 작업자 스레드가 GUI 관련 작업 자체를 시도하지 않도록하는 것이 중요합니다.

그러나 작업 을 작은 단계로 세분화 할 수없는 경우 일반 스레딩 유형 솔루션이 작동하지 않습니다. GUI는 스레드가 사용되는지 여부에 관계없이 작업이 완료 될 때까지 고정됩니다.

최종 시나리오의 경우 유일한 해결책은 multiprocessing 모듈을 사용하는 별도의 스레드가 아닌 프로세스 인을 사용하는 것입니다. 물론이 솔루션은 대상 시스템에 여러 개의 CPU 코어를 사용할 수있는 경우에만 효과적입니다. 함께 놀 수있는 CPU 코어가 하나 밖에 없다면, 기본적으로 파이썬의 다른 구현으로 전환하거나 다른 언어로 전환하는 것 이외에는 아무 것도 할 수 없습니다.

+0

이것을 실행하면 "응답하지 않음, 강제 종료"오류와 함께 GUI 창이 중지됩니다. 그러나 모든 작업이 완료 될 때까지 기다리면 일반 응용 프로그램이 계속됩니다. – Tuim

+1

@Tuim. 내 스크립트는 질문의 코드를 기반으로 한 간단한 데모 일뿐입니다. 그것은 모든 상황에서 작동 할 보편적 인 해결책은 아닙니다. 당신은 당신이하고자하는 것에 대한 적절한 설명으로 질문을 업데이트해야합니다. 당신이 언급하는 이러한 "과제"는 무엇입니까? CPU- 바운드입니까, 아니면 IO- 바운드입니까? 자신이 작성한 작업을 수행하는 응용 프로그램이 수정 될 수 있습니까? 어떤 언어로 쓰여졌습니까? 기타 등등 – ekhumoro

+0

이러한 작업은 zip 파일의 압축 풀기, msi/deb 패키지 설치 등의 작업입니다. 그러나 이것은이 사건과 관련이 없습니다. 이 응용 프로그램은 Python으로 작성되었으며 완벽하게 사용자 정의 할 수 있습니다. 또한 복사 - 붙여 넣기 가능 답변을 기대하지 않습니다! 나는 옳은 방향으로 힌트를 기대하고 있으며, 당신이 가진 것이 내가 올바른 방향으로 보이지 않았다고 시도했습니다. 범죄는 없습니다. – Tuim

0

gui 프로그래밍을 할 때 어떤 형태의 멀티 스레딩을 사용해야 할 때 작업자 스레드와 gui를 업데이트하고 마우스 및 키보드 이벤트에 응답하는 작업자 스레드가 필요합니다. 이를 수행하는 데는 여러 가지 방법이 있습니다. Q에서 QProgressBar를 사용하는 방법에 대한 우수한 작동 예제를 살펴 보시기 바랍니다.

튜토리얼에서는 튜토리얼에서 QBasicTimer를 사용하고 있습니다. QBasicTimer는 GUI 스레드에 응답 할 수 있도록 메인 스레드로 다시 제어 할 수있는 방법입니다. 코드에서 time.sleep을 사용하면 실행중인 유일한 스레드가 1 초 동안 차단됩니다.

+0

나는 알고있다. 그러나 그들은 예제 에서처럼 스레딩을 더 이상 사용하지 않습니다. – Tuim

+1

@Tuim : 그렇습니다.'time.sleep()'을 사용하지 마십시오. – Junuxx

+0

@Tuim 나는 코드와 튜토리얼이 같은 일을하지 않는 이유를 더 자세히 설명하기 위해 대답을 업데이트했다. –