PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。配布ライセンスは LGPL で公開されています。最新のバージョンは Qt6 に対応した PySide6(記事執筆時点で 6.2.2.1)です。
大きなファイルを読み込むときや、時間がかかる処理をしている時、GUI が反応しなくなります。自分用にちゃちゃっと作る GUI プログラムではそれでも我慢できますが、他の人も利用するようになったら、ちとダサいです。プログラムが固まると苦情を受けること必至です。ひと手間かけてスレッドで処理を分ければいいのですが、結局のところ、処理が終わるまでは他の処理をできなくして、進捗だけ表示させておけば良い場合が多いです。
そんなとき、QProgressDialog を利用すれば、進捗ダイアログで表示させ modal にしておけば、進捗を表示する上、親ウィンドウの操作ができなくなって便利です。
本記事では、下記の OS 環境を使用しています。
![]() |
Fedora Linux 35 Workstation | x86_64 |
まずは、ボタンをクリックしてダミーのタスクを実行し、その進捗を表示させるサンプルです。
#!/usr/bin/env python | |
# coding: utf-8 | |
import sys | |
import time | |
from PySide6.QtWidgets import ( | |
QApplication, | |
QMainWindow, | |
QProgressDialog, | |
QPushButton, | |
) | |
from PySide6.QtCore import ( | |
QThread, | |
Signal, Qt, | |
) | |
class Example(QMainWindow): | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
self.init_ui() | |
self.setWindowTitle('ProgressDialog & Thread') | |
self.resize(300, 100) | |
def init_ui(self): | |
but = QPushButton('START') | |
but.clicked.connect(self.task_start) | |
self.setCentralWidget(but) | |
def task_start(self): | |
button = self.sender() | |
button.setEnabled(False) | |
progress = QProgressDialog(labelText='Working...', parent=self) | |
progress.setWindowModality(Qt.WindowModal) | |
progress.setCancelButton(None) | |
progress.setWindowTitle('status') | |
progress.show() | |
task = TaskThread(self) | |
task.progressChanged.connect(progress.setValue) | |
task.start() | |
task.progressCompleted.connect(lambda: self.task_end(button, progress)) | |
def task_end(self, button, progress): | |
button.setEnabled(True) | |
progress.cancel() | |
class TaskThread(QThread): | |
progressChanged = Signal(int) | |
progressCompleted = Signal() | |
def run(self): | |
for progress in range(0, 101): | |
time.sleep(0.1) | |
self.progressChanged.emit(progress) | |
time.sleep(0.5) | |
self.progressCompleted.emit() | |
self.progressChanged.emit(0) | |
self.exit(0) | |
def main(): | |
app = QApplication(sys.argv) | |
ex = Example() | |
ex.show() | |
sys.exit(app.exec()) | |
if __name__ == '__main__': | |
main() |
一方、進捗を測る数字を取れない場合もあります。そんなときは、QProgressDialog の setRange メソッドで (0, 0) としておけば、進捗に関係なく進捗バーが動いているようになります。
#!/usr/bin/env python | |
# coding: utf-8 | |
import sys | |
import time | |
from PySide6.QtWidgets import ( | |
QApplication, | |
QMainWindow, | |
QProgressDialog, | |
QPushButton, | |
) | |
from PySide6.QtCore import ( | |
QThread, | |
Signal, Qt, | |
) | |
class Example(QMainWindow): | |
def __init__(self, parent=None): | |
super().__init__(parent) | |
self.init_ui() | |
self.setWindowTitle('ProgressDialog & Thread (2)') | |
self.resize(300, 100) | |
def init_ui(self): | |
but = QPushButton('START') | |
but.clicked.connect(self.task_start) | |
self.setCentralWidget(but) | |
def task_start(self, button): | |
button = self.sender() | |
button.setEnabled(False) | |
progress = QProgressDialog(labelText='Working...', parent=self) | |
progress.setWindowModality(Qt.WindowModal) | |
progress.setCancelButton(None) | |
progress.setRange(0, 0) | |
progress.setWindowTitle('status') | |
progress.show() | |
task = TaskThread(self) | |
task.start() | |
task.progressCompleted.connect(lambda: self.task_end(button, progress)) | |
def task_end(self, button, progress): | |
button.setEnabled(True) | |
progress.cancel() | |
class TaskThread(QThread): | |
progressCompleted = Signal() | |
def run(self): | |
for progress in range(0, 101): | |
time.sleep(0.1) | |
time.sleep(0.5) | |
self.progressCompleted.emit() | |
self.exit(0) | |
def main(): | |
app = QApplication(sys.argv) | |
ex = Example() | |
ex.show() | |
sys.exit(app.exec()) | |
if __name__ == '__main__': | |
main() |
QProgressDialog のダイアログ画面では、デフォルトでキャンセルボタンが表示されます。今回は良いサンプルを用意できなかったので、表示しないようにしてしまいましたが、サンプルを工夫できれば、あらためて紹介します。
参考サイト

にほんブログ村