수색…


소개

진행률 막대는 사용자 경험의 필수적인 부분이며 사용자가 GUI에서 실행되는 주어진 프로세스에 대한 시간에 대한 아이디어를 얻도록 도와줍니다. 이 항목에서는 자신의 응용 프로그램에서 진행률 막대를 구현하는 기본 사항에 대해 설명합니다.

이 주제는 QThread와 새로운 신호 / 슬롯 메커니즘을 가볍게 다룹니다. PyQt5 위젯에 대한 기본적인 지식 또한 독자들에게 기대된다.

예제를 추가 할 때는 PyQt5 및 Python 내장 기능 만 사용하여 기능을 시연하십시오.

PyQt5 전용

비고

이 예제를 실험하는 것이 학습을 시작하는 가장 좋은 방법입니다.

기본 PyQt 진행률 막대

이것은 매우 기본적인 진행 바입니다 만 최소한 필요한 것만 사용합니다.

이 모든 예를 끝까지 읽는 것이 현명 할 것입니다.

import sys
import time

from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar, QPushButton)

TIME_LIMIT = 100

class Actions(QDialog):
    """
    Simple dialog that consists of a Progress Bar and a Button.
    Clicking on the button results in the start of a timer and
    updates the progress bar.
    """
    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle('Progress Bar')
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.progress.setMaximum(100)
        self.button = QPushButton('Start', self)
        self.button.move(0, 30)
        self.show()

        self.button.clicked.connect(self.onButtonClick)

    def onButtonClick(self):
        count = 0
        while count < TIME_LIMIT:
            count += 1
            time.sleep(1)
            self.progress.setValue(count)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    sys.exit(app.exec_())

진행 막대는 from PyQt5.QtWidgets import QProgressBar

그런 다음 QtWidgets 다른 위젯처럼 초기화 QtWidgets

self.progress.setGeometry(0, 0, 300, 25) 메서드는 대화 상자의 x,y 위치와 진행률 막대의 너비와 높이를 정의합니다.

그런 다음 .move() 를 사용하여 버튼을 30px 아래쪽으로 이동하여 두 위젯 사이에 5px 의 간격이 5px .

여기서 self.progress.setValue(count) 는 진행 상황을 업데이트하는 데 사용됩니다. .setMaximum() 을 사용하여 최대 값을 설정하면 자동으로 값이 계산됩니다. 예를 들어 최대 값을 50으로 설정하면 TIME_LIMIT 가 100이므로 0 초에서 1 초에서 2 초가 아닌 0에서 2 ~ 4 퍼센트로 이동합니다. 또한 .setMinimum() 사용하여 최소값을 설정하여 진행률 막대가 주어진 값에서 시작되도록 할 수 있습니다.

이 프로그램을 실행하면 이와 유사한 GUI가 생성됩니다.

진행률 표시 줄 대화 상자가 응답하지 않음

보시다시피 카운터가 TIME_LIMIT 조건을 충족 할 때까지 GUI가 가장 명확하게 TIME_LIMIT 반응이 없습니다. 왜냐하면 time.sleep 은 OS가 프로그램이 무한 루프에 빠져 있다고 믿게하기 때문입니다.

QThread

그렇다면이 문제를 어떻게 극복 할 수 있습니까? 우리는 PyQt5가 제공하는 스레딩 클래스를 사용할 수 있습니다.

import sys
import time

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar, QPushButton)

TIME_LIMIT = 100

class External(QThread):
    """
    Runs a counter thread.
    """
    countChanged = pyqtSignal(int)

    def run(self):
        count = 0
        while count < TIME_LIMIT:
            count +=1
            time.sleep(1)
            self.countChanged.emit(count)

class Actions(QDialog):
    """
    Simple dialog that consists of a Progress Bar and a Button.
    Clicking on the button results in the start of a timer and
    updates the progress bar.
    """
    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle('Progress Bar')
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.progress.setMaximum(100)
        self.button = QPushButton('Start', self)
        self.button.move(0, 30)
        self.show()

        self.button.clicked.connect(self.onButtonClick)

    def onButtonClick(self):
        self.calc = External()
        self.calc.countChanged.connect(self.onCountChanged)
        self.calc.start()

    def onCountChanged(self, value):
        self.progress.setValue(value)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    sys.exit(app.exec_())

이 수정 사항을 분해합시다.

from PyQt5.QtCore import QThread, pyqtSignal

이 라인은 PyQt5 구현 인 Qthread 를 임포트하여 백그라운드에서 프로그램의 일부 (예 : 함수, 클래스)를 분할하고 실행합니다 (멀티 스레딩이라고도 함). 이러한 부분을 스레드라고도합니다. 모든 PyQt5 프로그램은 기본적으로 주 스레드를 가지고 있으며, 다른 프로그램 (작업 스레드)은 주 프로그램이 작동하는 동안 여분의 시간이 많이 소요되고 처리가 많은 작업을 백그라운드로 오프로드하는 데 사용됩니다.

두 번째 가져 오기 pyqtSignal 은 작업자와 주 스레드간에 데이터 (신호)를 보내는 데 사용됩니다. 이 예에서는 주 스레드가 진행률 표시 줄을 업데이트하도록 지시하기 위해이를 사용할 것입니다.

이제 counter에 대한 while 루프를 External 이라는 별개의 클래스로 옮겼습니다.

class External(QThread):
    """
    Runs a counter thread.
    """
    countChanged = pyqtSignal(int)

    def run(self):
        count = 0
        while count < TIME_LIMIT:
            count +=1
            time.sleep(1)
            self.countChanged.emit(count)

QThread 를 하위 클래스로 분류하여 External 을 본질적으로 별도의 스레드에서 실행할 수있는 클래스로 변환합니다. 스레드는 또한 언제든지 시작 또는 중지 할 수있어 이점을 누릴 수 있습니다.

여기서 countChanged 는 현재 진행 상태이며 pyqtSignal(int) 은 작업자 스레드에 신호 유형이 int 임을 알립니다. 반면 self.countChanged.emit(count) 는 주 스레드의 모든 연결에 신호를 보냅니다 (일반적으로 다른 작업자 스레드와도 통신하는 데 사용할 수 있음).

def onButtonClick(self):
        self.calc = External()
        self.calc.countChanged.connect(self.onCountChanged)
        self.calc.start()

def onCountChanged(self, value):
    self.progress.setValue(value)

버튼을 클릭하면 self.onButtonClick 이 실행되고 스레드도 시작됩니다. 스레드는 .start() 시작됩니다. 또한 앞에서 만든 self.calc.countChanged 신호를 진행률 막대 값을 업데이트하는 데 사용 된 메서드에 연결했음을 유의해야합니다. External::run::count 가 업데이트 될 때마다 int 값도 onCountChanged 전송됩니다.

이것은 GUI가 이러한 변경을 수행 한 후에 보일 수있는 방법입니다.

QThread 진행률 표시 줄

또한 반응이 훨씬 빨라 동결되지 않습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow