これは非常に基本的なプログレスバーで、最低限必要なものだけを使用します。
この全体の例を最後まで読むことは賢明でしょう。
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
ようにインポートされそしてラインself.progress.setGeometry(0, 0, 300, 25)
方法ダイアログと幅と高さにx,y
位置を定義QtWidgets
に他のウィジェットのように初期化されます進行状況バーの
次に、.move()
を使用して30px
をボタンを下に移動し、2つのウィジェットの間に隙間があるようにします(5px
)。
ここではself.progress.setValue(count)
が進捗の更新に使用されます。 .setMaximum()
を使用して最大値を設定すると、自動的に値が計算されます。たとえば、最大値が50と設定されている場合、TIME_LIMIT
が100であるため、毎秒0〜1〜2ではなく0〜2〜4%の範囲でホップします。 .setMinimum()
を使用して最小値を設定して、プログレスバーを強制的に所定の値から開始することもできます。
このプログラムを実行すると、これに類似したGUIが生成されます。
あなたが見ることができるようにカウンターがTIME_LIMIT
条件を満たすまで、GUIは、ほとんど間違いなくフリーズして反応しなくなります。これは、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_())
これらの変更を分解しましょう。分割していくつかの部分を実行するPyQt5
実装で
from PyQt5.QtCore import QThread, pyqtSignal
このラインの輸入Qthread
:バックグラウンドでのプログラムの(例えば、機能、クラスは、)(マルチスレッドとしても知られます)。これらの部分はスレッドとも呼ばれます。すべてのPyQt5
プログラムは、メインプログラムを維持したまま、デフォルトでメインスレッドを持ち、他のスレッド(ワーカースレッド)は余分な時間がかかり、処理が集中するタスクをバックグラウンドにオフロードするために使用されます。
第2のインポートpyqtSignal
は、ワーカーとメインスレッド間でデータ(信号)を送信するために使用されます。この例では、メインスレッドにプログレスバーを更新するように指示するために使用します。
今度はカウンタのwhileループをExternal
という別のクラスに移動しました。我々は本質的に別のスレッドで実行することができるクラスにExternal
を変換するQThread
をサブクラス化することによって
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)
。スレッドは、いつでもそのスレッドの利点を追加して開始または停止することができます。
ここでは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の外観です。
また、はるかに応答感じるべきと凍結しません。
PyQt4を使っていますが、これは本当に助けになりました –
@JuanCarlosAsuncion^_ ^ – daegontaven