응용 프로그램이 응답 할 수 있도록 루프가 실행되는 동안 이벤트를 처리하도록 허용해야합니다.
더 중요한 것은 장기 실행 작업의 경우 사용자가 루프를 시작한 후에 루프를 중지 할 수있는 방법을 제공해야한다는 것입니다.
이렇게하는 간단한 방법은 타이머를 사용하여 루프를 시작한 다음 루프가 실행되는 동안 주기적으로 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 코어가 하나 밖에 없다면, 기본적으로 파이썬의 다른 구현으로 전환하거나 다른 언어로 전환하는 것 이외에는 아무 것도 할 수 없습니다.
이것을 실행하면 "응답하지 않음, 강제 종료"오류와 함께 GUI 창이 중지됩니다. 그러나 모든 작업이 완료 될 때까지 기다리면 일반 응용 프로그램이 계속됩니다. – Tuim
@Tuim. 내 스크립트는 질문의 코드를 기반으로 한 간단한 데모 일뿐입니다. 그것은 모든 상황에서 작동 할 보편적 인 해결책은 아닙니다. 당신은 당신이하고자하는 것에 대한 적절한 설명으로 질문을 업데이트해야합니다. 당신이 언급하는 이러한 "과제"는 무엇입니까? CPU- 바운드입니까, 아니면 IO- 바운드입니까? 자신이 작성한 작업을 수행하는 응용 프로그램이 수정 될 수 있습니까? 어떤 언어로 쓰여졌습니까? 기타 등등 – ekhumoro
이러한 작업은 zip 파일의 압축 풀기, msi/deb 패키지 설치 등의 작업입니다. 그러나 이것은이 사건과 관련이 없습니다. 이 응용 프로그램은 Python으로 작성되었으며 완벽하게 사용자 정의 할 수 있습니다. 또한 복사 - 붙여 넣기 가능 답변을 기대하지 않습니다! 나는 옳은 방향으로 힌트를 기대하고 있으며, 당신이 가진 것이 내가 올바른 방향으로 보이지 않았다고 시도했습니다. 범죄는 없습니다. – Tuim