サーチ…


前書き

プログレスバーは、ユーザーエクスペリエンスの不可欠な部分であり、ユーザーが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

line self.progress.setGeometry(0, 0, 300, 25)メソッドは、ダイアログ上のx,y位置、および進行状況バーの幅と高さを定義します。

我々は次に、ボタンを使って移動.move()によって30pxのギャップが存在するであろう下方ように5px 2つのウィジェットの間です。

ここで、 self.progress.setValue(count)は進捗を更新するために使用されます。 .setMaximum()を使用して最大値を設定すると、自動的に値が計算されます。たとえば、最大値が50に設定されている場合、 TIME_LIMITは100であるため、1 TIME_LIMITではなくTIME_LIMIT %にホップします。また、 .setMinimum()を使用して最小値を設定して、進行状況バーを特定の値から開始させることもできます。

このプログラムを実行すると、これに類似したGUIが生成されます。

プログレスバーダイアログが応答しない

ご覧のとおり、GUIはTIME_LIMIT条件を満たしていないTIME_LIMIT 、フリーズして応答しなくTIME_LIMITます。これは、 time.sleepが、OSにプログラムが無限ループに陥っていると信じさせるためtime.sleep

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プログラムはメインスレッドを持ち、他のスレッド(ワーカースレッド)は、メインプログラムを機能させたまま、余分な時間がかかり、処理が集中するタスクをバックグラウンドにオフロードするために使用されます。

2番目のインポートpyqtSignalは、ワーカーとメインスレッド間でデータ(シグナル)を送信するために使用されます。この例では、メインスレッドにプログレスバーを更新するように指示するために使用します。

これで、カウンタの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送られonCountChanged

これは、これらの変更を行った後のGUIの見方です。

QThreadプログレスバー

それはまた、はるかに反応し、凍結することはありません感じる必要があります。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow