Pythonの「PyQt」は、クロスプラットフォーム対応のGUIアプリを作るためのライブラリです。GUIアプリの開発は難しいイメージがありますが、Pythonの「PyQt(パイキュート)」を使えば、高機能なGUIアプリが簡単に作れるようになります。
一方、PyQtは機能性が高いだけに、メソッドやウィジェットなどの種類が豊富です。そこで、「どう使えばいいかわからない」こと疑問に感じることもあるでしょう。今回は、PythonのGUIライブラリPyQtの使い方やテクニックについて、サンプルコード付きで解説します。
目次
Pythonの「PyQt(パイキュート)」とは、GUIアプリを開発するためのライブラリです。GUIとは「Graphical User Interface」のことでボタンやアイコンなど、グラフィックスを活用したプログラムを指します。GUIアプリはユーザーが簡単に使えるため、現在ではパソコンやスマホのアプリのほぼすべてが、GUIとなっています。
たとえば、インターネットを閲覧するときに使う「Google Chrome」や「Safari」、動画プラットフォームの「YouTube」などはすべてGUIアプリです。このようなGUIアプリを開発するために必要なのが、GUIライブラリです。GUIライブラリには、画像表示やユーザーのアクションに対応するために欠かせない、さまざまな機能が備わっています。
Pythonには、さまざまなGUIライブラリがありますが、その中でもPyQtは機能性やデザイン性が高いGUIアプリが作れるため、さまざまな場面で活用されています。なお、PyQtはバージョンアップが続けられており、現在では「PyQt5」や「PyQt6」が一般的です。なお、本記事では互換性を考慮して、すべてPyQt5でのソースコードを掲載しています。
PythonのPyQtを使うことで、以下3つのメリットが得られます。
PyQtを利用すると、GUIアプリ・プログラムが簡単に作れるようになります。テキスト主体のCUI(Character User Interface)とは異なり、GUIアプリの開発には高度なスキルが要求されます。そのため、GUIプログラミングは「難しい」「気軽にできない」と思われがちです。たとえば、ウィンドウを表示するだけでも、複雑なソースコードを書かないといけません。
しかし、PyQtではごく短いコードを書くだけで、ウィンドウはもちろん画像やボタンなどを簡単に表示できます。高機能なGUIアプリを作る場合は、PyQt特有のメソッドやウィジェットへの理解を覚える必要はありますが、PyQtは全体的に簡潔で扱いやすい構造になっています。そのため、GUIプログラミングの初心者でも、気軽にチャレンジしやすいでしょう。
PyQtを活用すると、「クロスプラットフォーム」対応のGUIアプリが作れます。クロスプラットフォームとは、簡単に言うと「さまざまなデバイス・環境で同じように動作できる」ことです。
たとえば、パソコンのOSには大きく分けて、WindowsとmacOSの2種類があります。それぞれまったく異なる思想・設計で構成されているため、片方のOSに向けて作られたソフトウェアは、もう一方のOSでは動作しません。したがって、複数のOSに対応したアプリを作るためには、それぞれのOSごとに異なるソースコードでプログラムを開発しないといけません。
しかし、クロスプラットフォームに対応したソフトウェアは、複数のOSで同じように動作します。PyQtでは、Windows・macOS・Linuxに対応したアプリが作れるため、さまざまなユーザーにアプリを提供したいときに便利です。
Pythonで使えるGUIライブラリには、さまざまな種類があります。その中でも、PyQtは現在でも積極的な開発・アップデートが行われているライブラリなので、設計自体が「モダン」です。GUI画面のデザインの自由度が高いため、「見栄えがするアプリ」を作れます。
旧式のGUIライブラリを使っていると、「思うようにデザインできない」ことがあります。PyQtはボタンやテキストなどのデザインを変更したり、画像やアイコンを挿入したりすることが可能です。また、設計自体がモダンであることから、GUIに関する複雑な処理も簡潔に記載できることが魅力です。
PythonのPyQtを使うデメリットとして、以下の3つがあげられます。
PyQtは、公式ドキュメントの日本語版がないため、日本語で得られる情報量が少なめです。GUIプログラミングに慣れていない初心者にとっては、公式情報を得にくいことが気になるかもしれません。
しかし、PyQtの基本的なメソッドやウィジェットなどについては、公式以外のサイトやブログにて日本語で情報が公開されているため、問題解決の手段は比較的充実しているといえるでしょう。本記事でも、PyQtの基本的な使い方を解説します。
Python自体が「動作速度が遅い」言語として知られていますが、PyQtはグラフィックス処理を行うため、さらに動作速度が低下する傾向があります。GUIプログラミングの主流な手段として「C++」がありますが、PyQtのGUIアプリはC++で開発したものと比べて、動作速度は大幅に低い水準になります。動作速度が重要なアプリを開発する場合は、PyQtでも問題ないか事前に確認しておくほうが良いでしょう。
PyQtは、TkinterやPyGameなどのGUIライブラリと比べて、「ライセンス」の条件が厳しい点もデメリットです。
PyQtで開発したプログラムやアプリを販売する場合は、商用ライセンスを有償で取得しないといけません。また、PyQtは「GPLライセンス」であるため、非商用・商用を問わず、すべてのソースコードを公開する必要があります。
したがって、商用目的のアプリをPyQtで開発した場合は、収益面で不利になる可能性が高いです。すべてのソースコードを公開することで、競合開発者も同様のプログラムを容易に開発できるようになるからです。
そのため、商用目的でGUIプログラムやアプリを開発する場合は、TkinterやPyGameなど、ほかのGUIライブラリを利用するほうが良いでしょう。
PyQtは、Pythonに標準搭載されているライブラリではありません。そのため、Windows PCの場合は、以下の手順でPyQtをインストールする必要があります。まずは、「コマンドプロンプト」を開いて、以下のコマンドを入力してください。
py -m pip install PyQt5
このコマンドは、Pythonパッケージのインストールなどを行うユーティリティで、PyQt5をインストールするというものです。なお、前述したように2023年現在では「PyQt6」が最新バージョンですが、導入のしやすさや互換性の観点から「PyQt5」を使用します。
続いて、「SIP」というツールも準備します。SIPは、C++で作成されたプログラムを、Pythonで利用するためのものです。PythonでPyQt5を使うためには、以下のコマンドでSIPをインストールする必要があります。
py -m pip install SIP
以上すべてのコマンドを入力すると、以下のような画面が表示されてインストールの完了となります。
PyQtの基本的なウィジェットの使い方について、以下4つのポイントから解説します。
GUIプログラミングの第一歩は「ウィンドウの生成」です。PyQtでは、QMainWindowクラスの「show()関数」を呼び出すとウィンドウが表示されます。ただし、ウィンドウのさまざまな機能を便利に使うために、「QMainWindowクラス」を継承したクラスを作成することが一般的です。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QMainWindowクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ウィンドウを表示する self.show() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
上記のプログラムでは、QMainWindowクラスを継承した「Programクラス」を作成しています。コンストラクタでQMainWindowクラスを初期化してから、show()を呼び出していることがポイントです。なお、setWindowTitle()でウィンドウタイトルを、setGeometry()でウィンドウサイズを設定できます。
「from PyQt5.QtCore import *」と「from PyQt5.QtWidgets import*」は、それぞれ「PyQt5.QtCore」と「PyQt5.QtWidgets」の内部にあるすべてのモジュールをimportするということです。初心者が学習するときは、ワイルドカードを使うほうがわかりやすいためおすすめです。
簡易的な情報を表示するための「ステータスバー」は、「self.statusBar().showMessage()メソッド」で表示できます。なお、QMainWindowクラスを継承していなければ、この機能は使えないので注意が必要です。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ウィンドウを表示する self.show() # ステータスバーを表示する self.statusBar().showMessage("ステータスバーの情報") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
上記のように、メインウィンドウの下部にステータスバーが表示されます。このステータスバーに、プログラムの進行状況を表示するようにすると、よりユーザーフレンドリーなGUIアプリが作れるでしょう。
ステータスバーに簡易的な時計を表示したい場合は、QTimerオブジェクトを生成します。QTimerオブジェクトの「timeout.connect()関数」の引数に、現在日時を表示するためのメソッドを指定すればOKです。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # 「datetimeモジュール」をインポートする import datetime # 「localeモジュール」をインポートする import locale # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # システムロケールを設定する # setlocale()を呼び出さなければ、PyQtで日本語を表示できない locale.setlocale(locale.LC_ALL, "") # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ウィンドウを表示する self.show() # QTimerを初期化する timer = QTimer(self) # timeoutシグナルに「getDateTime()メソッド」をスロットとして指定する timer.timeout.connect(self.getDateTime) # タイマーの動作を開始する timer.start() # getDateTime()メソッド|ステータスバーに現在日時を表示する def getDateTime(self): # 現在の日時を取得する time = datetime.datetime.today() # 取得した日時をフォーマット済み文字列形式に変換する string = time.strftime(u"%Y年%m月%d日 %H時%M分%S秒") # ステータスバーに現在日時を表示する self.statusBar().showMessage(f"現在時刻:{string}") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
現在日時を表示するための「getDateTime()メソッド」の内部では、datetime.datetime.today()で取得した日時を文字列に変換し、statusBar().showMessage()の引数に引き渡しています。
なお、Programクラスのコンストラクタで「locale.setlocale()」という関数を呼び出していますが、これはプログラム内で日本語を表示するためのものです。この工程を挟んでおかなければ、文字化けやエラーが発生してしまうので注意が必要になることを留意します。
また、PyQtでは「シグナル」と「スロット」という概念が重要です。シグナルは、プログラム内でアクションや変化が起きたときに発生し、スロットでその対応を行います。上記のサンプルプログラムの場合は、タイマーのタイムアウト時に「timer.timeoutシグナル」が発生し、「getDateTime()メソッド」をスロットとしています。こうすることで、自動的にステータスバーの内容が変更されるようになるので便利です。
GUIプログラムでは、ユーザーがさまざまな処理や操作を行うために、メニューバーの存在が欠かせません。メニューバーは、まずメニューバーオブジェクトを「menuBar()」で作成し、その「addMenu()」を呼び出してメニュー項目を追加します。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # メニューバーを表示する self.setMenuBar() # ウィンドウを表示する self.show() # setMenuBar()メソッド|メニューバーを生成する def setMenuBar(self): # メニューバーを生成する menubar = self.menuBar() # メニューバーに「ファイル」項目を追加する fileMenu = menubar.addMenu("ファイル") # 「終了」アクションを作成する exitAction = QAction("終了", self) # 「終了」アクションのショートカットを設定する exitAction.setShortcut("Ctrl+Q") # 「終了」アクションのステータスバーのメッセージを設定する exitAction.setStatusTip("プログラムを終了します") # 「終了」アクションとqApp.quit()メソッドを関連付ける exitAction.triggered.connect(qApp.quit) # メニューバーの「ファイル」項目に「終了」アクションを追加する fileMenu.addAction(exitAction) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
「終了」アクションにマウスカーソルを合わせたとき
上記のサンプルプログラムでは、メニュー項目の「アクション」も設定しています。まずQActionオブジェクトを作成し、その「triggered.connect()」にスロットを設定しましょう。ショートカットは「setShortcut()」、ステータスバーのメッセージは「setStatusTip()」で設定可能です。そのうえで、addAction()の引数にアクションを指定すれば、便利なメニューバーを作成できます。
PythonのPyQtを活用するためには、GUI画面の部品である「ウィジェット」を使いこなすことが重要です。今回は、PyQtの主要ウィジェット13種類について解説します。
「QLabel(ラベル)」は、GUI画面にラベルを表示するためのウィジェットです。QLabelオブジェクトを生成し、setText()でテキストの文字列を設定できます。さらに、setFont()・setFrameStyle()・setLineWidth()などで、詳細の設定が可能です。QLabelウィジェットの使い方について、以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ラベルを生成する label = QLabel(self) # ラベルに表示するテキストを設定する label.setText("サンプルテキスト") # テキストのフォントを設定する label.setFont(QtGui.QFont("メイリオ", 30, QtGui.QFont.Bold)) # 枠線のスタイルを設定する label.setFrameStyle(QFrame.Box | QFrame.Raised) # 枠線の太さを設定する label.setLineWidth(5) # ラベルのサイズをテキストに合わせる label.adjustSize() # 枠の中心にテキストを表示するようにする label.setAlignment(Qt.AlignCenter) # ラベルの位置をX座標50・Y座標120に設定する label.move(50, 120) # ウィンドウを表示する self.show() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
上記のサンプルプログラムでは、フォントやスタイルを指定したラベルを作成しています。setFrameStyle()で「QFrame.Raised」を指定しているため、立体的な印象になっています。PyQtは、こうしたデザインも簡単にできることが魅力です。なお、後述する「レイアウト」を使用しない場合は、ウィジェットのサイズを調整する必要があります。adjustSize()を呼び出すことで、内容に合わせたサイズへの自動調整となります。
「QPushButton(プッシュボタン)」ウィジェットは、クリックできる通常のボタンです。QPushButtonオブジェクトを生成すると、プッシュボタンを表示できます。setDefault()でデフォルトの状態、setFlat()でフラットボタンかどうか、setCheckable()でトグルボタンかどうかを設定可能です。setChecked()を呼び出せば、トグルボタンの初期状態を指定できます。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # 3つのボタンを生成する button_1 = QPushButton("ボタン1", self) button_2 = QPushButton("ボタン2", self) button_3 = QPushButton("ボタン3", self) # 「ボタン1」はデフォルト状態で押された状態にする # setDefault()を呼び出さない場合は「False」となる button_1.setDefault(True) # 「ボタン2」をフラットボタンにする button_2.setFlat(True) # 「ボタン3」をトグルボタンにする # setChecked()で初期状態を設定する button_3.setCheckable(True) button_3.setChecked(False) # 各ボタンの位置とサイズを設定する button_1.setGeometry(200, 100, 200, 50) button_2.setGeometry(200, 200, 200, 50) button_3.setGeometry(200, 300, 200, 50) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
トグルボタンを押したとき
ボタンが押されたときにアクションを起こしたいときは、ボタンの「clicked.connect()メソッド」に、アクションの内容を記載したメソッドを指定します。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ボタンを生成する button = QPushButton("終了", self) # 各ボタンの位置とサイズを設定する button.setGeometry(200, 100, 200, 50) # clickedシグナルに「qApp.quit()メソッド」をスロットとして指定する # ボタンを押すとプログラムが終了する button.clicked.connect(qApp.quit) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
1行だけテキストを入力できる項目を追加するときは、「QLineEdit(ラインエディット)」ウィジェットを使用しましょう。QLineEditオブジェクトを生成するだけで、ユーザーが1行だけ入力できるテキストボックスが表示されます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # テキストボックスを生成する self.line = QLineEdit("テキストを入力してください", self) # テキストボックスの表示位置とサイズを設定する self.line.setGeometry(120, 150, 350, 50) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
テキスト入力後
なお、QLineEditオブジェクトのsetEchoMode()メソッドの引数に「QLineEdit.EchoMode.Password」を指定すると、パスワードモードになり、入力した文字列が隠蔽されます。また、「textChangedシグナル」に任意のメソッドをスロットとして指定すると、テキスト変更時にそのメソッドが自動的に呼び出されます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ラベルを生成する label = QLabel("パスワード", self, font = QtGui.QFont("メイリオ", 15)) # ラベルの表示位置を設定する label.move(120, 80) # ラベルのサイズをテキストに合わせる label.adjustSize() # テキストボックスを生成する self.line = QLineEdit(self) # テキストボックスを生成する self.line.setEchoMode(QLineEdit.EchoMode.Password) # テキストボックスの表示位置とサイズを設定する self.line.setGeometry(120, 150, 350, 50) # textChangedシグナルに「getNewText()メソッド」をスロットとして指定する # テキストが変更されたときはgetNewText()が自動的に呼び出される self.line.textChanged.connect(self.getNewText) # getNewText()メソッド|新しいテキストを表示する def getNewText(self): # text()メソッドを呼び出すことで、テキストボックスの文字列が取得できる print(f"入力されたパスワード:{self.line.text()}") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
GUI画面
コンソール画面
上記のサンプルプログラムでは、ユーザーがテキストボックスの内容を変更するたびに、その内容がコンソール画面に表示されます。textChangedシグナルに指定したgetNewText()メソッド内部では、text()を呼び出してテキストボックスの文字列を取得していることがポイントです。
改行できるテキストボックスを設置したい場合は、「QTextEdit(テキストエディット)」を使用しましょう。QTextEditオブジェクトを生成すると、ユーザーが自由に入力・編集できるテキストボックスが表示されます。なお、「font引数」で好みのフォントを指定することで、見やすいテキストボックスになります。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # テキストボックスを生成する self.text = QTextEdit("テキストを入力してください", self, font = QtGui.QFont("メイリオ", 10)) # テキストボックスの表示位置とサイズを設定する self.text.setGeometry(10, 10, 620, 460) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
テキスト入力時
テキストの内容を取得したい場合は、QTextEditオブジェクトの「toPlainText()メソッド」を呼び出すことで、ユーザーが入力した文字列を取得できます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # フォント情報を生成する self.font = QtGui.QFont("メイリオ", 10) # テキストボックスを生成する self.text = QTextEdit("テキストを入力してください", self, font = self.font) # テキストボックスの表示位置とサイズを設定する self.text.setGeometry(10, 10, 620, 400) # ボタンを生成する button = QPushButton("入力完了", self, font = self.font) # ボタンの位置を設定する button.move(250, 430) # clickedシグナルに「getText()メソッド」をスロットとして指定する # 「入力完了」ボタンをクリックしたときに、このメソッドが自動的に呼び出される button.clicked.connect(self.getText) # getText()メソッド|新規テキストを画面に表示する def getText(self): print(self.text.toPlainText()) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
GUI画面
コンソール画面
上記のサンプルプログラムでは、ユーザーが「入力完了」ボタンを押すと、テキストボックスに入力したテキストがコンソール画面に表示されます。このように、ボタンクリックでアクションを起こすケースが多いので、一連の流れに慣れておきましょう。
先ほど紹介したQPushButtonは横長のボタンなので、アイコンの表示には不向きです。ツールバーに表示するような正方形のボタンを使用したい場合は、「QToolButton(ツールボタン)」を使用しましょう。QToolButtonオブジェクトを生成し、setIcon()メソッドに「QIconオブジェクト」を引き渡すことで、ボタンにアイコンを表示できます。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QIcon # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ボタンを生成する button = QToolButton(self) # ボタンのアイコンを設定する button.setIcon(QIcon(self.style().standardPixmap(QStyle.SP_DialogOpenButton))) # ボタンのテキストを設定する button.setText("終了"); # テキストの表示形式を設定する # 「ToolButtonTextBesideIcon」はアイコンの横 # 「ToolButtonTextUnderIcon」はアイコンの下 button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon); # ボタンのサイズを合わせる button.adjustSize() # clickedシグナルに「qApp.quit()メソッド」をスロットとして指定する # ボタンを押すとプログラムが終了する button.clicked.connect(qApp.quit) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
上記のサンプルプログラムでは、アイコンとテキストをボタン内に併記しています。QIconオブジェクトの生成時は、style().standardPixmap()メソッドを呼び出し、アイコンの種類を選ぶ必要があるでしょう。今回の例では、ダイアログを開くアイコンである「QStyle.SP_DialogOpenButton」です。
また、アイコンとテキストを併記するときは、setToolButtonStyle()メソッドで表示形式を指定できます。テキストの表示形式は、以下の5種類から選びます。
テキストの表示形式 | 概要 |
---|---|
ToolButtonIconOnly | アイコンのみ表示する |
ToolButtonTextOnly | テキストのみ表示する |
ToolButtonTextBesideIcon | アイコンの横にテキストを表示する |
ToolButtonTextUnderIcon | アイコンの下にテキストを表示する |
ToolButtonFollowStyle | スタイルに従って表示する |
複数の選択肢から1つだけ選べるようにしたい場合は、「QRadioButton(ラジオボタン)」ウィジェットを使用します。QRadioButtonオブジェクトを生成することで、ラジオボタンの原型が整います。詳細を以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # 3つのラジオボタンを生成する radio_button_1 = QRadioButton("ラジオボタン1", self) radio_button_2 = QRadioButton("ラジオボタン2", self) radio_button_3 = QRadioButton("ラジオボタン3", self) # 「ラジオボタン1」はデフォルト状態で押された状態にする # setChecked()を呼び出さない場合は「False」となる radio_button_1.setChecked(True) # 各ラジオボタンのサイズをテキストに合わせる radio_button_1.adjustSize() radio_button_2.adjustSize() radio_button_3.adjustSize() # 各ラジオボタンの位置を設定する radio_button_1.move(200, 100) radio_button_2.move(200, 200) radio_button_3.move(200, 300) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
ボタンクリック時
以上のように、1つしか選べないボタンが表示されます。ただし、クリックしたときにアクションを起こすなど、ラジオボタンとして正しく機能させるためには、以下のように「QButtonGroupオブジェクト」にラジオボタンを追加する必要があります。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # 3つのラジオボタンを生成する radio_button_1 = QRadioButton("ラジオボタン1", self) radio_button_2 = QRadioButton("ラジオボタン2", self) radio_button_3 = QRadioButton("ラジオボタン3", self) # 各ラジオボタンのサイズをテキストに合わせる radio_button_1.adjustSize() radio_button_2.adjustSize() radio_button_3.adjustSize() # 各ラジオボタンの位置を設定する radio_button_1.move(200, 100) radio_button_2.move(200, 200) radio_button_3.move(200, 300) # ボタングループを生成する self.button_group = QButtonGroup() # 各ラジオボタンをボタングループに追加する self.button_group.addButton(radio_button_1) self.button_group.addButton(radio_button_2) self.button_group.addButton(radio_button_3) # buttonClickedシグナルに「getClickedButton()メソッド」をスロットとして指定する # スロットの引数には自動的に押されたボタンが引き渡される self.button_group.buttonClicked.connect(self.getClickedButton) # getClickedButton()メソッド|クリックされたボタンを取得する def getClickedButton(self, button): # 「button.text()メソッド」を呼び出すことで、ボタンのテキストを取得できる print(f"「{button.text()}」がクリックされました") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
ボタンクリック時
QButtonGroupオブジェクトを生成したあとで、addButton()メソッドの引数に各ラジオボタンを指定することで、すべてのボタンがグループ化されます。そのオブジェクトのbuttonClicked.connect()にスロットを設定することで、どのボタンがクリックされたときでも同じメソッドが呼び出されるようになります。
複数の選択肢を自由に選べるチェックボックスは、「QCheckBoxウィジェット」で作成できます。ただし、QRadioButtonとは異なりQButtonGroupを使用しません。QButtonGroupを使用した場合は複数チェックができず、チェックボックスとしての機能を果たさなくなるので注意が必要です。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # チェックボックスを生成する check_box_1 = QCheckBox(f"チェックボックス1", self) check_box_2 = QCheckBox(f"チェックボックス2", self) check_box_3 = QCheckBox(f"チェックボックス3", self) # 各チェックボックスのサイズをテキストに合わせる check_box_1.adjustSize() check_box_2.adjustSize() check_box_3.adjustSize() # 各チェックボックスの位置を設定する check_box_1.move(200, 100) check_box_2.move(200, 200) check_box_3.move(200, 300) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
チェックボックスのクリック時
チェックボックスの「toggled.connect()」シグナルに、任意のスロットを指定すればOKです。ただし、通常の方法ではチェックボックスごとに、スロットを作成しないといけないのが不便なところ。そこで以下のサンプルコードのように、「クロージャー(関数内関数)」を使用するのがおすすめです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # 3つのチェックボックス・オブジェクトを格納するためのリスト check_boxes = [None] * 3 # 3つのチェックボックスを生成する for i in range(3): # チェックボックスを生成する check_boxes[i] = QCheckBox(f"チェックボックス{i + 1}", self) # チェックボックスのサイズをテキストに合わせる check_boxes[i].adjustSize() # チェックボックスの位置を設定する check_boxes[i].move(200, 100 * (i + 1)) # toggledシグナルに「checkBoxClicked()メソッド」をスロットとして指定する # スロットの引数にはチェックの状態が引き渡される check_boxes[i].toggled.connect(self.checkBoxClicked(i)) # checkBoxClicked()メソッド|チェックボックスのクリック時のアクション # 引数としてチェックボックス番号を受ける def checkBoxClicked(self, i): # スロットをネストする「クロージャー(関数内関数)」として定義する # 引数としてボックスのチェック状態を受ける def inner(checked): print(f"「チェックボックス{str(i + 1)}」のチェック状態は「{checked}」です") # 間接的にcheckBoxClicked()メソッドを呼び出す return inner # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
チェックボックスのクリック時
コンソール画面
関数の中にある関数を「クロージャー(関数内関数)」と呼びます。クロージャーの特徴は、外側の関数の変数を記憶している点です。上記のサンプルプログラムの場合は、inner()内部でcheckBoxClicked()の引数である「i」が記憶されています。そのため、toggled.connect()でスロットを指定するときに指定したインデックス「i」で、どのチェックボックスがクリックされたか判定することが可能です。
このように、複数のチェックボックスを配列で管理したり、クロージャーを活用したりすると、ソースコードを大幅に簡潔化できます。
ウィンドウに画像を表示したいときは、「QPixmap(ピクセルマップ)」ウィジェットを活用しましょう。QPixmapオブジェクトの生成時に画像ファイルを指定することで、画像データを表示する準備が自動的に整います。あとはQLabelオブジェクトを生成し、setPixmap()メソッドで画像をはめ込めばOKです。今回は、以下の画像を「Flower.jpg」という名称でメインモジュールと同じディレクトリに保存し、次のサンプルコードを実行しましょう。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ラベルを生成する # 画像はラベルに埋め込む label = QLabel(self) # QPixmapオブジェクトで画像を読み込む pixmap = QPixmap("Flower.jpg") # 画像の横幅をウィンドウサイズに合わせる pixmap = pixmap.scaledToWidth(640) # ラベルに画像を挿入する label.setPixmap(pixmap) # ラベルのサイズを画像に合わせる label.adjustSize() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
このように、PyQtでは非常に簡単な手順で画像やイラストを表示できます。なお、「style().standardPixmap()メソッド」を活用すると、標準で搭載されているアイコン画像を使うことも可能です。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ラベルを生成する # アイコンはラベルに埋め込む label_computer = QLabel(self) label_drive = QLabel(self) label_open = QLabel(self) label_apply = QLabel(self) # ラベルの位置とサイズを設定する label_computer.setGeometry(0, 0, 100, 100) label_drive.setGeometry(120, 0, 100, 100) label_open.setGeometry(240, 0, 100, 100) label_apply.setGeometry(360, 0, 100, 100) # ラベルにアイコン挿入する label_computer.setPixmap(self.style().standardPixmap(QStyle.SP_ComputerIcon)) label_drive.setPixmap(self.style().standardPixmap(QStyle.SP_DriveHDIcon)) label_open.setPixmap(self.style().standardPixmap(QStyle.SP_DirOpenIcon)) label_apply.setPixmap(self.style().standardPixmap(QStyle.SP_DialogApplyButton)) # アイコンのサイズを画像に合わせる label_computer.setScaledContents(True); label_drive.setScaledContents(True); label_open.setScaledContents(True); label_apply.setScaledContents(True); # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
style().standardPixmap()メソッドに、使用するアイコンを指定することで、ラベルにアイコンを表示できます。代表的な標準アイコンは以下のとおりです。
SP_TitleBarMenuButton | タイトルバーのメニューボタン |
SP_TitleBarMinButton | タイトルバーの最小化ボタン |
SP_TitleBarMaxButton | タイトルバーの最大化ボタン |
SP_TitleBarCloseButton | タイトルバーの閉じるボタン |
SP_TitleBarNormalButton | タイトルバーの通常ボタン |
SP_TitleBarShadeButton | タイトルバーの隠すボタン |
SP_TitleBarUnshadeButton | タイトルバーの表示ボタン |
SP_TitleBarContextHelpButton | タイトルバーのヘルプボタン |
SP_MessageBoxInformation | インフォメーション |
SP_MessageBoxWarning | 警告マーク |
SP_MessageBoxCritical | 致命的エラー |
SP_MessageBoxQuestion | 質問マーク |
SP_DesktopIcon | デスクトップ |
SP_TrashIcon | ゴミ箱 |
SP_ComputerIcon | コンピューター |
SP_DirOpenIcon | 開いているディレクトリ |
SP_DirClosedIcon | 閉じているディレクトリ |
SP_DirLinkIcon | リンクディレクトリ |
SP_FileDialogStart | ファイルダイアログの開始 |
SP_FileDialogEnd | ファイルダイアログの終了 |
SP_FileDialogToParent | ファイルダイアログの親ディレクトリ |
左右に動かすことで値を変更できるスライダーは、「QSliderウィジェット」で表示できます。QSliderオブジェクトを生成し、setMinimum()・setMaximum()・setValue()などのメソッドを呼び出すことで、スライダーの仕様を設定できます。valueChanged.connect()メソッドで、値が変更されたときのスロットを設定可能です。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # スライダーの初期値を設定する initial_value = 100 # スライダーの個数を設定する self.num_sliders = 5 # ウィジェットを生成する widget = QWidget() # ラベルを生成する self.labels = [QLabel() for x in range(self.num_sliders)] # ラベルの初期値を設定する for x in self.labels: x.setText(str(initial_value)) # スライダーを生成する self.sliders = [QSlider(Qt.Orientation.Horizontal) for x in range(self.num_sliders)] # 各スライダーの仕様を設定する for each_slider in self.sliders: # 最小値 each_slider.setMinimum(10) # 最大値 each_slider.setMaximum(1000) # 初期値 each_slider.setValue(initial_value) # valueChangedシグナルに「getNewValues()メソッド」をスロットとして指定する each_slider.valueChanged.connect(self.getNewValues) # GridLayoutオブジェクトを生成する layout = QGridLayout() # ラベルとスライダーをレイアウトに追加する for i in range(self.num_sliders): layout.addWidget(self.labels[i], i, 0) layout.addWidget(self.sliders[i], i, 1) # レイアウト適用済みのウィジェットをメインウィンドウに追加する widget.setLayout(layout) self.setCentralWidget(widget) # getNewValues()メソッド|スライダー変更時に新しい値を取得する def getNewValues(self): # 各スライダーの値をラベルに反映させる for i in range(self.num_sliders): # スライダーの「value()メソッド」で値を取得できる self.labels[i].setText(str(self.sliders[i].value())) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
スライダー変更時
上記のように、スライダーのダイヤルを動かすことで、自由に値を変更できます。etNewValues()メソッドの内部では、スライダーの値をラベルに反映させていることがポイントです。なお、今回はグリッドと値を並べて表示するために、QGridLayoutオブジェクトというレイアウト機能を使用しています。レイアウトの詳細については後述します。
「QDial(ダイアル)ウィジェット」は、回転させることで値を変更するためのものです。QDialオブジェクトを生成し、setValue()関数で初期値を設定できます。
valueChanged.connect()の引数で、値が変更されたときのスロットを指定可能です。QDialの使い方を以下のサンプルコードで確認しましょう。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ダイアルを生成する dial = QDial(self) # ダイアルの最小値と最大値を設定する dial.setRange(-100, 100) # ダイアルの初期値を設定する dial.setValue(0) # ダイアルのvalueChangedシグナルに「getValue()メソッド」をスロットとして指定する dial.valueChanged.connect(self.getValue) # ダイアルウィジェットの位置とサイズを設定する dial.setGeometry(100, 100, 300, 300) # ラベルを生成する self.label = QLabel("±000", self) # テキストのフォントを設定する self.label.setFont(QtGui.QFont("メイリオ", 30, QtGui.QFont.Bold)) # ラベルウィジェットの位置とサイズを設定する self.label.setGeometry(400, 300, 200, 100) # getValue()メソッド|ダイアルの値をラベルに表示する def getValue(self, value): # 変更後の「value」の値をラベルに設定する self.label.setText(str(value)) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
ダイアル変更後
データの読み込みや処理を行うときなどに、その進行状況を表示したいことがあるでしょう。「QProgressBar(プログレスバー)」を使用すると、プロセスの進行状況を可視化できます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # 「threadingモジュール」をインポートする import threading # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する widget = QWidget() # プログレスバーを生成する self.bar = QProgressBar() # 初期値を「50」に設定する self.bar.setValue(50) # GridLayoutオブジェクトを生成する layout = QGridLayout() # プログレスバーをレイアウトに追加する layout.addWidget(self.bar) # レイアウト適用済みのウィジェットをメインウィンドウに追加する widget.setLayout(layout) self.setCentralWidget(widget) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
なお、プログレスバーは以下のように自由に進行できます。今回は、メインウィンドウの「ステータスバー」に、プログレスバーを埋め込むサンプルプログラムをご紹介しましょう。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # 「threadingモジュール」をインポートする import threading # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # プログレスバーを進行させる self.progress() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する widget = QWidget() # プログレスバーを生成する self.bar = QProgressBar() # メインウィンドウのステータスバーに、プログレスバーを埋め込む self.statusBar().addWidget(self.bar); # 初期値を「0」に設定する self.bar.setValue(0) # progress()メソッド|プログレスバーを進行させる def progress(self): # プログレスバーの進行度 value = 0 # プログレスバーが100になるまで無限ループを回す while True: # 無限forループなどを回していると、GUI画面が固まってしまう。 # そこで、毎ループ「QApplication.processEvents()メソッド」を呼び出すことにより、 # 未処理のイベントを済ませてから、forループの処理に戻ることができる。 # 引数に「QEventLoop.ExcludeUserInputEvents」を指定すると、 # ウィジェットなどに対するユーザーの入力を防げるため、想定外の動作を防げて安全 QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) # プログレスバーの値を更新する self.bar.setValue(value) # プログレスバーを1だけ進める # 値が100を超えた場合は処理を終了する value += 1 if(value > 100): break # 0.05秒だけ待機する time.sleep(0.05) # 1秒待機する time.sleep(1) # 処理の完了後は、ステータスバーからプログレスバーを削除して、完了メッセージを表示する self.statusBar().removeWidget(self.bar) self.statusBar().showMessage("処理が完了しました!") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
処理進行中
処理完了後
無限ループを回し、その中でプログレスバーのsetValue()を呼び出し、値を増やしていることがポイントです。time.sleep()を活用し、1ループあたり0.05秒ずつ待つことで、プログレスバーが徐々に増えます。
また、「QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)」と記載することで、forループ中にGUI画面が固まるのを防ぐことが可能です。この処理を挟まなければ、無限ループが終わるまで、ユーザーは画面を一切操作できないようになってしまいます。
マルチスレッドを使うのもひとつの方法ですが、マルチスレッドは扱いが非常に難しく、想定外のバグやエラーの原因になりやすいことが難点です。QApplication.processEvents()を呼び出すことで、GUI画面のフリーズを簡単に防げるのでおすすめです。
「QCalendarWidget(カレンダーウィジェット)」を使えば、以下のようにGUI画面にカレンダーを表示させることもできます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # 「threadingモジュール」をインポートする import threading # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # カレンダーを生成する calendar = QCalendarWidget(self) # カレンダーの位置を設定する calendar.move(50, 50) # カレンダーのサイズを調整する calendar.adjustSize() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
「QDateTimeEdit(デートタイムエディット)」を使うと、より詳細な情報を表示できるうえに、値を変更できるカレンダーを表示できます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # 「threadingモジュール」をインポートする import threading # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # カレンダーを生成する self.calendar = QDateTimeEdit(self) # 現在日時をカレンダーのデフォルトとする self.calendar.setDateTime(QDateTime.currentDateTime()) # クリック時にカレンダーを表示する self.calendar.setCalendarPopup(True) # カレンダーの位置とサイズを設定する self.calendar.setGeometry(100, 50, 200, 50) # 日時が変更されたときは「calendar_changed()関数」を呼び出す self.calendar.dateTimeChanged.connect(self.calendar_changed) # calendar_changed()メソッド|カレンダー変更時のメソッド def calendar_changed(self): # dateTime().toString()で変更後の日時を取得可能 print(self.calendar.dateTime().toString("yyyy/MM/dd HH:mm:ss")) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
日時の変更時
コンソール画面
GUI画面を自由に作り出すためには、「レイアウト」機能を使うことも重要です。PyQtでは、以下の4種類のレイアウトが使えます。
「QHBoxLayout」は、ウィジェットを横に並べるためのレイアウトです。QHBoxLayoutオブジェクトを生成してから、addWidget()関数でウィジェットを指定すると、指定した順番どおりにウィジェットが横に並びます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QHBoxLayoutオブジェクトを生成する layout = QHBoxLayout() # 4つのラベルを生成する label_1 = QLabel("テキスト1", self) label_2 = QLabel("テキスト2", self) label_3 = QLabel("テキスト3", self) label_4 = QLabel("テキスト4", self) # QHBoxLayoutオブジェクトに4つのラベルを追加する layout.addWidget(label_1) layout.addWidget(label_2) layout.addWidget(label_3) layout.addWidget(label_4) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
なお、最初にQWidgetオブジェクトを生成し、最後にsetLayout()関数の引数として、QHBoxLayoutオブジェクトを引き渡していることがポイントです。そのうえで、setCentralWidget()でQWidgetオブジェクトを指定すれば、レイアウトを反映できます。メインウィンドウにレイアウトを指定すると、エラーになるので注意が必要です。
「QVBoxLayout」は、ウィジェットを縦に並べるためのレイアウトです。先ほどのQHBoxLayoutオブジェクトと同じく、addWidget()関数でウィジェットを指定すると、指定した順番どおりにウィジェットが縦に並びます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # 4つのラベルを生成する label_1 = QLabel("テキスト1", self) label_2 = QLabel("テキスト2", self) label_3 = QLabel("テキスト3", self) label_4 = QLabel("テキスト4", self) # QVBoxLayoutオブジェクトに4つのラベルを追加する layout.addWidget(label_1) layout.addWidget(label_2) layout.addWidget(label_3) layout.addWidget(label_4) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
「QGridLayout」は、ウィジェットを縦横のグリッド状に並べるためのレイアウトです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QGridLayoutオブジェクトを生成する layout = QGridLayout() # 4つのラベルを生成する label_1 = QLabel("テキスト1", self) label_2 = QLabel("テキスト2", self) label_3 = QLabel("テキスト3", self) label_4 = QLabel("テキスト4", self) # QGridLayoutオブジェクトに4つのラベルを追加する layout.addWidget(label_1, 0, 0) layout.addWidget(label_2, 0, 1) layout.addWidget(label_3, 1, 0) layout.addWidget(label_4, 1, 1) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
QGridLayoutオブジェクトを生成したうえで、addWidget()関数を呼び出しましょう。第2引数に横方向・第3引数に縦方向の番号を指定することで、ウィジェットがグリッド状に並びます。
「QFormLayout」は、「ラベル+入力フォーム」のようなセットのウィジェットを、複数並べるためのものです。一連のセットを、QFormLayoutオブジェクトのaddRow()メソッドで並べ、各セットをQHBoxLayoutもしくはQVBoxLayoutで配置します。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する # Widgetオブジェクトには1つのレイアウトしか設定できないため、 # 2つのQFormLayoutオブジェクトを追加してから、 # QVBoxLayoutオブジェクトをWidgetオブジェクトに反映させる layout_0 = QVBoxLayout() # 2つのQFormLayoutオブジェクトを生成する # ラベル+テキストボックスのペアを配置する layout_1 = QFormLayout() layout_2 = QFormLayout() # 4つのラベルを生成する label_1 = QLabel("テキスト1", self) label_2 = QLabel("テキスト2", self) label_3 = QLabel("テキスト3", self) label_4 = QLabel("テキスト4", self) # 4つのテキストボックスを生成する text_1 = QLineEdit() text_2 = QLineEdit() text_3 = QLineEdit() text_4 = QLineEdit() # 1つ目のQFormLayoutオブジェクトに、2組のラベル+テキストボックスのペアを追加する layout_1.addRow(label_1, text_1) layout_1.addRow(label_2, text_2) # 2つ目のQFormLayoutオブジェクトに、2組のラベル+テキストボックスのペアを追加する layout_2.addRow(label_3, text_3) layout_2.addRow(label_4, text_4) # QVBoxLayoutオブジェクトに、2つのQFormLayoutオブジェクトを追加する layout_0.addLayout(layout_1) layout_0.addLayout(layout_2) # Widgetオブジェクトに、QVBoxLayoutオブジェクトのレイアウトを反映させる widget.setLayout(layout_0) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
上記のサンプルプログラムのように、入力フォームを作成するなどの場合に、QFormLayoutが役立ちます。
ユーザーフレンドリーなGUIアプリを作るためには、「ダイアログ」を活用することも重要です。ダイアログを表示すれば、ユーザーにさまざまな情報を伝えられます。PyQtでは、以下のようにさまざまなダイアログも表示できます。
「QInputDialog(インプットダイアログ)」は、ユーザーにデータを入力してもらうためのダイアログです。「getText」「getMultiLineText」「getItem」「getInt」「getDouble」の5種類があります。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # ボタンを生成する single_button = QPushButton("1行テキスト", self) multi_button = QPushButton("複数行テキスト", self) item_button = QPushButton("アイテム", self) int_button = QPushButton("整数値", self) double_button = QPushButton("浮動小数点値", self) # 各ボタンのサイズをテキストに合わせる single_button.adjustSize() multi_button.adjustSize() item_button.adjustSize() int_button.adjustSize() double_button.adjustSize() # 各ボタンのclickedシグナルにスロットを指定する single_button.clicked.connect(self.showSingleDialog) multi_button.clicked.connect(self.showMultiDialog) item_button.clicked.connect(self.showItemDialog) int_button.clicked.connect(self.showIntDialog) double_button.clicked.connect(self.showDoubleDialog) # QVBoxLayoutオブジェクトに5つのボタンを追加する layout.addWidget(single_button) layout.addWidget(multi_button) layout.addWidget(item_button) layout.addWidget(int_button) layout.addWidget(double_button) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # showSingleDialog()メソッド|1行テキストのダイアログを表示する def showSingleDialog(self): # 「getText」のダイアログを表示する # 第2引数はタイトル # 第3引数はメッセージ text, is_ok = QInputDialog.getText(self, "ダイアログ", "テキストを入力してください") # 入力されたテキストを表示する if is_ok: print(text) # showMultiDialog()メソッド|複数行テキストのダイアログを表示する def showMultiDialog(self): # 「getMultiLineText」のダイアログを表示する # 第2引数はタイトル # 第3引数はメッセージ text, is_ok = QInputDialog.getMultiLineText(self, "ダイアログ", "テキストを入力してください") # 入力されたテキストを表示する if is_ok: print(text) # showItemDialog()メソッド|アイテムのダイアログを表示する def showItemDialog(self): # アイテムのリストを設定する items = ["選択肢A", "選択肢B", "選択肢C", "選択肢D", "選択肢E"] # 「getItem」のダイアログを表示する # 第2引数はタイトル # 第3引数はメッセージ # 第4引数はアイテムのリスト # 第5引数はデフォルトの選択肢 # 第6引数は選択肢を編集可能かどうか text, is_ok = QInputDialog.getItem(self, "ダイアログ", "テキストを入力してください", items, 0, False) # 選択されたアイテムを表示する if is_ok: print(text) # showIntDialog()メソッド|整数値のダイアログを表示する def showIntDialog(self): # 「getInt」のダイアログを表示する # 第2引数はタイトル # 第3引数はメッセージ # 第4引数は初期値 # 第5引数は最小値 # 第6引数は最大値 # 第7引数は増減値 text, is_ok = QInputDialog.getInt(self, "ダイアログ", "テキストを入力してください", 0.0, 100.0, -100.0, 5) # 入力された整数値を表示する if is_ok: print(text) # showDoubleDialog()メソッド|浮動小数点値のダイアログを表示する def showDoubleDialog(self): # 「getDouble」のダイアログを表示する # 第2引数はタイトル # 第3引数はメッセージ # 第4引数は初期値 # 第5引数は最小値 # 第6引数は最大値 # 第7引数は小数部の桁数 text, is_ok = QInputDialog.getDouble(self, "ダイアログ", "テキストを入力してください", 0.0, -100.0, 100.0, 3) # 入力された浮動小数点値を表示する if is_ok: print(text) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
メイン画面
getText
getMultiLineText
getItem
getInt
getDouble
各ボタンをクリックすることで、インプットダイアログが表示されます。ユーザーの入力値は、ダイアログの戻り値として取得できます。
「QFileDialog(ファイルダイアログ)」は、ファイル入出力を行うためのダイアログです。ファイルを開く場合は「QFileDialog.getOpenFileName」、保存する場合は「QFileDialog.getSaveFileName」を使用します。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # 2つのボタンを生成する open_button = QPushButton("ファイルを開く", self) save_button = QPushButton("ファイルを保存する", self) # 各ボタンの位置を設定する open_button.move(110, 100) save_button.move(100, 200) # 各ボタンのサイズをテキストに合わせる open_button.adjustSize() save_button.adjustSize() # 各ボタンのclickedシグナルにメソッドをスロットとして指定する open_button.clicked.connect(self.openFile) save_button.clicked.connect(self.saveFile) # openFile()メソッド|ファイルを開くダイアログを表示する def openFile(self): # QFileDialog.getOpenFileName()メソッドで、ファイルを開くダイアログを表示する # 第2引数はダイアログのタイトル、第3引数は最初のパス、第4引数はフィルターを設定する filename = QFileDialog.getOpenFileName(self, "ファイルを開く", "./", "Image files (*.bmp *.jpg *.png *.tif);;Any files (*.*)") # ファイルが選択されている場合は、ファイル名を表示する if filename[0] != "": print(f"「{filename[0]}」が選択されました") # saveFile()メソッド|ファイルを開くダイアログを表示する def saveFile(self): # QFileDialog.getSaveFileName()メソッドで、ファイルを開くダイアログを表示する # 第2引数はダイアログのタイトル、第3引数は最初のパス、第4引数はフィルターを設定する filename = QFileDialog.getSaveFileName(self, "ファイルを保存する", "./", "Image files (*.bmp *.jpg *.png *.tif);;Any files (*.*)") # ファイルが選択されている場合は、ファイル名を表示する if filename[0] != "": print(f"「{filename[0]}」が選択されました") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
ファイルを開く
ファイルを保存する
なお、ダイアログ関数の引数は、第2引数がダイアログのタイトル・第3引数が最初のパス・第4引数がフィルターとなっています。フィルターを設定することで、どの拡張子のファイルをオープン・セーブできるか指定可能です。
「QColorDialog.getColor()メソッド」で、カラーダイアログを表示できます。カラーダイアログは、ユーザーが自由に「色」を選べるので便利です。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # ボタンを生成する button = QPushButton("カラー", self) # 各ボタンのサイズをテキストに合わせる button.adjustSize() # 各ボタンのclickedシグナルに「showColorDialog()メソッド」をスロットとして指定する button.clicked.connect(self.showColorDialog) # QVBoxLayoutオブジェクトにボタンを追加する layout.addWidget(button) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # showColorDialog()メソッド|カラーダイアログを表示する def showColorDialog(self): # QColorDialogダイアログを表示する # 第1引数は初期設定のカラー # 第3引数はダイアログのタイトル # 第4引数はオプション(ここでは「アルファチャンネルを表示」を指定) color = QColorDialog.getColor(Qt.white, self, "カラーダイアログ", QColorDialog.ShowAlphaChannel) # 有効なカラーが指定された場合は、コンソール画面にRGBAの順番で表示する if color.isValid(): print(color.getRgb()) # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
カラーダイアログ
色を指定するとき
コンソール画面
ダイアログの「Pick Screen Color」を選べば、画面上の色をピックアップできるので非常に便利です。
「QFontDialog(フォントダイアログ)」は、フォントを選択するためのダイアログ。GUI画面上に設置することで、ユーザーが自由にフォントを選択できます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # ボタンを生成する button = QPushButton("フォント", self) # 各ボタンのサイズをテキストに合わせる button.adjustSize() # 各ボタンのclickedシグナルに「showFontDialog()メソッド」をスロットとして指定する button.clicked.connect(self.showFontDialog) # QVBoxLayoutオブジェクトにボタンを追加する layout.addWidget(button) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # showFontDialog()メソッド|フォントダイアログを表示する def showFontDialog(self): # QFontDialogダイアログを表示する # 第1引数は初期設定のフォント # 第3引数はダイアログのタイトル font, is_ok = QFontDialog.getFont(QtGui.QFont("メイリオ", 10), self, "フォントダイアログ") # コンソール画面にフォント情報で表示する if is_ok: print(f"フォント名「{font.family()}」\nサイズ「{font.pointSize()}」\nウェイト「{font.weight()}」\nイタリック「{font.italic()}」\nボールド「{font.bold()}」\nStrikeout「{font.strikeOut()}」\nUnderline「{font.underline()}」") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
フォントダイアログ
フォント選択時
コンソール画面
「QProgressDialog(プログレスダイアログ)」は、プロセスの進行状況を表示するためのダイアログです。QProgressDialogの生成時に、メッセージと最小値・最大値を指定でき、setWindowModalityでモダリティの指定もできます。モーダルダイアログを使用し、プログレスダイアログを表示する手順は以下のとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # ボタンを生成する button = QPushButton("プログラム処理を進行する", self) # 各ボタンのサイズをテキストに合わせる button.adjustSize() # 各ボタンのclickedシグナルに「showProgressDialog()メソッド」をスロットとして指定する button.clicked.connect(self.showProgressDialog) # QVBoxLayoutオブジェクトにボタンを追加する layout.addWidget(button) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # showProgressDialog()メソッド|プログレスダイアログを表示する def showProgressDialog(self): # プログレスダイアログを表示する # 第1引数はメッセージ # 第2引数は処理を中止するボタンのテキスト # 第3引数は進行状況の最小値 # 第4引数は進行状況の最大値 progress = QProgressDialog("処理を行っています…", "中止する", 0, 100, self) # ウィンドウのモダリティを設定する # 「Qt.WindowModal(モーダルダイアログ)」もしくは「Qt.NonModal(モードレスダイアログ)」を選択 # Qt.WindowModalは、ダイアログが終了するまでメインウィンドウを操作できない # Qt.NonModalは、ダイアログ進行中でもメインウィンドウを操作できる # Qt.WindowModalを選ぶのが無難で、Qt.NonModalは基本的に使わない progress.setWindowModality(Qt.WindowModal) # ダイアログのタイトルを設定する progress.setWindowTitle("プログレスダイアログ") # ダイアログのサイズを設定する progress.setFixedSize(500, 250) # ダイアログを表示する progress.show() # forループでダイアログを進行させる for i in range(100): # 無限forループなどを回していると、GUI画面が固まってしまう。 # そこで、毎ループ「QApplication.processEvents()メソッド」を呼び出すことにより、 # 未処理のイベントを済ませてから、forループの処理に戻ることができる。 # 引数に「QEventLoop.ExcludeUserInputEvents」を指定すると、 # ウィジェットなどに対するユーザーの入力を防げるため、想定外の動作を防げて安全 QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) # ダイアログの進行度を設定する progress.setValue(i) # 0.05秒だけ待機する time.sleep(0.05) # キャンセルボタンがクリックされたときは、処理を終了する if progress.wasCanceled(): break; # 最後にダイアログの進行度をMAXにする progress.setValue(100); # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
ダイアログ
処理進行中
大容量ファイルの入出力など時間がかかる処理を行うときは、プログレスダイアログを表示すると、ユーザーフレンドリーなGUIアプリになるでしょう。
「QPrintDialog(プリントダイアログ)」は、ドキュメントを印刷するためのダイアログです。まず、QPrinterオブジェクトを準備したうえで、QPrintDialogを生成します。戻り値が「QDialog.Accepted」であれば、実際の印刷処理を行います。今回は、ユーザーがテキストボックスに入力したテキストを印刷するための、サンプルコードをご紹介します。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「QTextDocument」「QPrintDialog」「QPrinter」モジュールをインポートする from PyQt5.QtGui import QTextDocument from PyQt5.QtPrintSupport import QPrintDialog, QPrinter # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # ラベルを生成する label = QLabel("テキストを入力してください", self) # テキストボックスを生成する self.text = QTextEdit(self) # ボタンを生成する button = QPushButton("印刷する", self) # 各ボタンのサイズをテキストに合わせる button.adjustSize() # 各ボタンのclickedシグナルに「showPrinterDialog()メソッド」をスロットとして指定する button.clicked.connect(self.showPrinterDialog) # QVBoxLayoutオブジェクトに各ウィジェットを追加する layout.addWidget(label) layout.addWidget(self.text) layout.addWidget(button) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # showPrinterDialog()メソッド|プリンターダイアログを表示する def showPrinterDialog(self): # QPrinterオブジェクトを生成する printer = QPrinter(QPrinter.HighResolution) # QPrintDialogを表示する dialog = QPrintDialog(printer, self) # ダイアログで「印刷」がクリックされたら、入力されたテキストを印刷する if dialog.exec() == QDialog.Accepted: # QTextDocumentオブジェクトを生成する document = QTextDocument(); # ユーザーが入力したテキストをドキュメントに反映する document.setPlainText(self.text.toPlainText()); # ドキュメントを印刷する document.print(printer); # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
テキスト入力画面
プリンターダイアログ
PDF化したドキュメント
Windows PCの場合は、「Microsoft Print to PDF」を選択すると、仮想プリンターとしてテキストドキュメントをPDF化できます。ドキュメントをPDF化する機会は多いので、実用的なプログラムだといえるでしょう。
「QMessageBox(メッセージボックス)」は、ユーザーに単純なメッセージを表示するためのダイアログです。以下のサンプルコードのように、「information(情報)」「warning(警告)」「critical(エラー)」「question(確認)」の4種類のダイアログが選べます。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # ボタンを生成する button_information = QPushButton("情報", self) button_warning = QPushButton("警告", self) button_critical = QPushButton("エラー", self) button_question = QPushButton("確認", self) # 各ボタンのclickedシグナルのスロットを指定する button_information.clicked.connect(self.showInformationBox) button_warning.clicked.connect(self.showWarningBox) button_critical.clicked.connect(self.showCriticalBox) button_question.clicked.connect(self.showQuestionBox) # QVBoxLayoutオブジェクトに各ボタンを追加する layout.addWidget(button_information) layout.addWidget(button_warning) layout.addWidget(button_critical) layout.addWidget(button_question) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # showInformationBox()メソッド|Informationメッセージボックスを表示する def showInformationBox(self): QMessageBox.information(self, "情報", "メッセージ") # showWarningBox()メソッド|Warningメッセージボックスを表示する def showWarningBox(self): QMessageBox.warning(self, "警告", "メッセージ") # showCriticalBox()メソッド|Criticalメッセージボックスを表示する def showCriticalBox(self): QMessageBox.critical(self, "エラー", "メッセージ") # showQuestionBox()メソッド|Questionメッセージボックスを表示する def showQuestionBox(self): QMessageBox.question(self, "確認", "メッセージ") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
情報
警告
エラー
確認
PyQtでは、カスタムのメッセージボックスも作成できるのが魅力です。QMessageBoxを生成し、追加したいボタンをaddButton()関数で指定します。この関数では「StandardButton」を指定でき、以下のような種類があります。
ボタン | 概要 | 役割 |
---|---|---|
QMessageBox.Ok | 了解 | AcceptRole |
QMessageBox.Open | 開く | AcceptRole |
QMessageBox.Save | 保存 | AcceptRole |
QMessageBox.Cancel | キャンセル | RejectRole |
QMessageBox.Close | 閉じる | RejectRole |
QMessageBox.Discard | 破棄 | DestructiveRole |
QMessageBox.Apply | 適用する | ApplyRole |
QMessageBox.Reset | リセット | ResetRole |
QMessageBox.RestoreDefaults | デフォルトに戻す | ResetRole |
QMessageBox.Help | ヘルプ | HelpRole |
QMessageBox.SaveAll | すべて保存 | AcceptRole |
QMessageBox.Yes | はい | YesRole |
QMessageBox.YesToAll | すべてはい | YesRole |
QMessageBox.No | いいえ | NoRole |
QMessageBox.NoToAll | すべていいえ | NoRole |
QMessageBox.Abort | 異常終了 | RejectRole |
QMessageBox.Retry | 再試行 | AcceptRole |
QMessageBox.Ignore | 無視 | AcceptRole |
QMessageBox.NoButton | ボタンなし | なし |
上記以外のオリジナルのボタンを追加したいときは、addButtonの第1引数にボタンテキスト、第2引数に「ボタンの役割」を指定します。ボタンの役割として、以下のようなものを指定できます。
役割 | 概要 |
---|---|
InvalidRole | 無効 |
AcceptRole | 受諾(OK) |
RejectRole | 拒否(Canel) |
DestructiveRole | 変更の破棄 |
ActionRole | 要素の変更 |
HelpRole | ヘルプの要求 |
YesRole | 「はい」ボタン |
NoRole | 「いいえ」ボタン |
ResetRole | デフォルトの復帰 |
ApplyRole | 変更の適用 |
なお、exec()メソッドの戻り値は「StandardButton」しかないため、オリジナルボタンを使用した場合は、このメソッドでクリックされたボタンの判定ができません。そのため、clickedButton()関数を使用する必要があります。メッセージボックスの表示後、QMessageBoxオブジェクトの「clickedButton()」を呼び出すことで、ユーザーが選択したボタンがわかります。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する # メインウィンドウにレイアウトを直接指定するとエラーになるため、 # まずWidgetオブジェクトに各要素を入れて、レイアウトを設定してから、 # Widgetオブジェクトをメインウィンドウに配置する widget = QWidget() # QVBoxLayoutオブジェクトを生成する layout = QVBoxLayout() # 2つのボタンを生成する button_default = QPushButton("デフォルトのメッセージボックス", self) button_original = QPushButton("オリジナルのメッセージボックス", self) # 各ボタンのclickedシグナルのスロットを指定する button_default.clicked.connect(self.showDefaultMessageBox) button_original.clicked.connect(self.showOriginalMessageBox) # QVBoxLayoutオブジェクトに各ボタンを追加する layout.addWidget(button_default) layout.addWidget(button_original) # Widgetオブジェクトにレイアウトを反映させる widget.setLayout(layout) # ウィジェットにレイアウトを設定する self.setCentralWidget(widget) # showDefaultMessageBox()メソッド|デフォルトのカスタムメッセージボックスを表示する def showDefaultMessageBox(self): # QMessageBoxオブジェクトを生成する message_box = QMessageBox(self) # メッセージボックスのタイトルを設定する message_box.setWindowTitle("確認") # メッセージボックスのテキストを設定する message_box.setText("これでよろしいですか?") # 「確認アイコン」を設定する message_box.setIcon(QMessageBox.Question) # 「Yes」「No」「Cancel」のボタンを追加する message_box.addButton(QMessageBox.Yes) message_box.addButton(QMessageBox.No) message_box.addButton(QMessageBox.Cancel) # デフォルトのボタンを「Cencel」に設定する message_box.setDefaultButton(QMessageBox.Cancel) # メッセージボックスを表示する result = message_box.exec() # 「Yes」が選択されたら処理開始のメッセージを表示する if result == QMessageBox.Yes: print("処理を開始します…") # showOriginalMessageBox()メソッド|オリジナルのカスタムメッセージボックスを表示する def showOriginalMessageBox(self): # QMessageBoxオブジェクトを生成する message_box = QMessageBox(self) # メッセージボックスのタイトルを設定する message_box.setWindowTitle("エラー") # メッセージボックスのテキストを設定する message_box.setText("処理中に致命的なエラーが発生しました") # 「エラーアイコン」を設定する message_box.setIcon(QMessageBox.Critical) # 「再チャレンジする」ボタンを「受諾」用途で追加する button_1 = message_box.addButton("再チャレンジする", QMessageBox.AcceptRole) # 「データを破棄する」ボタンを「破棄」用途で追加する button_2 = message_box.addButton("データを破棄する", QMessageBox.DestructiveRole) # 「前の画面に戻る」ボタンを「リセット」用途で追加する button_3 = message_box.addButton("前の画面に戻る", QMessageBox.ResetRole) # デフォルトのボタンを「Cencel」に設定する message_box.setDefaultButton(button_3) # メッセージボックスを表示する message_box.exec() # clickedButton()メソッドで、クリックしたボタンを取得する clicked = message_box.clickedButton() # 「再チャレンジする」が選択された場合 if clicked == button_1: print("「再チャレンジする」が選択されました") # 「データを破棄する」が選択された場合 elif clicked == button_2: print("「データを破棄する」が選択されました") # 「前の画面に戻る」が選択された場合 else: print("「前の画面に戻る」が選択されました") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
デフォルトのメッセージボックス
オリジナルのメッセージボックス
コンソール画面
上記のサンプルプログラムでは、「デフォルトのメッセージボックス」と「オリジナルのメッセージボックス」の双方を表示し、その違いを確認できます。
ここまでに解説したさまざまなメソッドやウィジェットの知識を活かすと、よりハイレベルなGUIアプリを作成できることを覚えておきましょう。今回は一例として、以下の2つの応用例をご紹介します。
ツールボタンやアイコン、テキストボックスやファイルダイアログなどを組み合わせると、簡易的なテキストエディタを作成できます。テキストファイルの読み込みや保存に加えて、テキストボックスのフォントを変更することも可能です。以下のサンプルコードを参考にして、オリジナルのテキストエディタを作ってみましょう。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「QtGuiモジュール」をインポートする from PyQt5 import QtGui from PyQt5.QtGui import QIcon from PyQt5.QtGui import QPixmap # 「sipモジュール」をインポートする import sip # 「timeモジュール」をインポートする import time # 「threadingモジュール」をインポートする import threading # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # PyQtのウィンドウを生成する self.createWindow() # createWindow()メソッド|PyQtのウィンドウを生成する def createWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ウィジェットを生成する self.initWidget() # ウィンドウを表示する self.show() # initWidget()メソッド|ウィジェットを生成する def initWidget(self): # ウィジェットを生成する widget = QWidget() # 4つのボタンを生成する button_open = QToolButton() button_save = QToolButton() button_font = QToolButton() button_desc = QToolButton() # 各ボタンのアイコンを設定する button_open.setIcon(QIcon(self.style().standardPixmap(QStyle.SP_DialogOpenButton))) button_save.setIcon(QIcon(self.style().standardPixmap(QStyle.SP_DialogSaveButton))) button_font.setIcon(QIcon(self.style().standardPixmap(QStyle.SP_FileDialogContentsView))) button_desc.setIcon(QIcon(self.style().standardPixmap(QStyle.SP_MessageBoxQuestion))) # 各ボタンのテキストを設定する button_open.setText("読み込み"); button_save.setText("保存"); button_font.setText("フォント"); button_desc.setText("概要"); # テキストの表示形式を設定する # 「ToolButtonTextBesideIcon」はアイコンの横 # 「ToolButtonTextUnderIcon」はアイコンの下 button_open.setToolButtonStyle(Qt.ToolButtonTextUnderIcon); button_save.setToolButtonStyle(Qt.ToolButtonTextUnderIcon); button_font.setToolButtonStyle(Qt.ToolButtonTextUnderIcon); button_desc.setToolButtonStyle(Qt.ToolButtonTextUnderIcon); # clickedシグナルに「qApp.quit()メソッド」をスロットとして指定する # ボタンを押すとプログラムが終了する button_open.clicked.connect(self.button_open_clicked) button_save.clicked.connect(self.button_save_clicked) button_font.clicked.connect(self.button_font_clicked) button_desc.clicked.connect(self.button_desc_clicked) # QGridLayoutオブジェクトを生成する layout = QGridLayout() # 各ボタンを配置する layout.addWidget(button_open, 0, 0, 1, 1) layout.addWidget(button_save, 0, 1, 1, 1) layout.addWidget(button_font, 0, 2, 1, 1) layout.addWidget(button_desc, 0, 3, 1, 1) # テキストボックスを生成する self.text = QTextEdit("テキストを入力してください", self, font = QtGui.QFont("メイリオ", 10)) # テキストボックスを配置する layout.addWidget(self.text, 1, 0, 1, 5) # レイアウト適用済みのウィジェットをメインウィンドウに追加する widget.setLayout(layout) self.setCentralWidget(widget) # button_open_clicked()メソッド|テキストファイルを読み込んでテキストボックスに表示する def button_open_clicked(self): # QFileDialog.getOpenFileName()メソッドで、ファイルを開くダイアログを表示する # 第2引数はダイアログのタイトル、第2引数は最初のパス、第4引数はフィルターを設定する filename = QFileDialog.getOpenFileName(self, "ファイルを開く", "./", "Text files (*.txt);;Any files (*.*)") # ファイルが選択されている場合は、ファイルの中身をテキストボックスに反映する if filename[0] != "": # 「読み込みモード」でファイルを開き、テキストデータを読み込む data = open(filename[0], "r", encoding = "UTF-8") text = data.read() data.close() # テキストボックスにテキストを反映させる self.text.setPlainText(text) # プログレスバーを表示する self.progress() # button_save_clicked()メソッド|テキストボックスのデータをテキストファイルに書き出す def button_save_clicked(self): # QFileDialog.getSaveFileName()メソッドで、ファイルを開くダイアログを表示する # 第2引数はダイアログのタイトル、第2引数は最初のパス、第4引数はフィルターを設定する filename = QFileDialog.getSaveFileName(self, "ファイルを保存する", "./", "Text files (*.txt);;Any files (*.*)") # ファイルが選択されている場合は、テキストボックスのデータをテキストファイルに書き出す if filename[0] != "": # 「書き込みモード」でファイルを開き、テキストデータを書き出す data = open(filename[0], "w", encoding = "UTF-8") data.write(self.text.toPlainText()) data.close() # プログレスバーを表示する self.progress() # button_font_clicked()メソッド|「フォント」ボタンをクリックしたときの処理を行う def button_font_clicked(self): # QFontDialogダイアログを表示する # 第1引数は初期設定のフォント # 第3引数はダイアログのタイトル font, is_ok = QFontDialog.getFont(QtGui.QFont("メイリオ", 10), self, "フォントダイアログ") # コンソール画面にフォント情報で表示する if is_ok: # テキストボックスのフォントに反映する self.text.setFont(QtGui.QFont(font.family(), pointSize = font.pointSize(), italic = font.italic(), weight = font.weight())) # button_desc_clicked()メソッド|「概要」ボタンをクリックしたときの処理を行う def button_desc_clicked(self): # メッセージボックスでプログラムの概要を表示する QMessageBox.information(self, "情報", "本プログラムは簡易的なテキストエディタです。\nテキストファイルの読み込みと書き出しが行えます。") # progress()メソッド|プログレスバーを進行させる def progress(self): # プログレスバーを生成する bar = QProgressBar() # メインウィンドウのステータスバーに、プログレスバーを埋め込む self.statusBar().addWidget(bar); # プログレスバーの進行度 value = 0 # プログレスバーが100になるまで無限ループを回す while True: # 無限forループなどを回していると、GUI画面が固まってしまう。 # そこで、毎ループ「QApplication.processEvents()メソッド」を呼び出すことにより、 # 未処理のイベントを済ませてから、forループの処理に戻ることができる。 # 引数に「QEventLoop.ExcludeUserInputEvents」を指定すると、 # ウィジェットなどに対するユーザーの入力を防げるため、想定外の動作を防げて安全 QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) # プログレスバーの値を更新する bar.setValue(value) # プログレスバーを1だけ進める # 値が100を超えた場合は処理を終了する value += 1 if(value > 100): break # 0.001秒だけ待機する time.sleep(0.001) # 処理の完了後は、ステータスバーからプログレスバーを削除して、完了メッセージを表示する self.statusBar().removeWidget(bar) self.statusBar().showMessage("処理が完了しました!") # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期画面
「読み込みボタン」クリック時
「保存ボタン」クリック時
「フォントボタン」クリック時
「概要ボタン」クリック時
フォント変更後
上記のように、GUI画面上には4つのツールボタンが表示され、その下にテキストボックスがあります。それぞれのボタンをクリックすると、ファイルの読み込みや保存、フォントの設定などが可能です。なお、本プログラムで作成したテキストファイルは、メモ帳などのテキストエディタでも使えます。
さらに機能を発展させるために、文字列の検索や置換などの機能を搭載すると、より便利なテキストエディタになるでしょう。
GUIライブラリの「PyQt」と、グラフ描画用のライブラリである「Matplotlib」を組み合わせれば、GUI画面にグラフを表示することもできます。詳細は以下のサンプルコードのとおりです。
//サンプルプログラム
# coding: UTF-8 # 「sysモジュール」をインポートする import sys # 「datetimeモジュール」をインポートする import datetime # 「localeモジュール」をインポートする import locale # 「randomモジュール」をインポートする import random # 「PyQt」のモジュール群をインポートする from PyQt5.QtCore import * from PyQt5.QtWidgets import * # 「matplotlib」のモジュール群をインポートする from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure import matplotlib.pyplot as pyplot # Programクラス|PyQtの処理を実行する # さまざまな機能を搭載した「QMainWindowクラス」を継承する class Program(QMainWindow): # コンストラクタ def __init__(self): # QWidgetクラスを初期化する super().__init__() # システムロケールを設定する locale.setlocale(locale.LC_ALL, "") # PyQtのウィンドウを生成する self.initWindow() def initWindow(self): # ウィンドウのタイトルを設定する self.setWindowTitle("PyQtサンプルプログラム") # ウィンドウのサイズを設定する self.setGeometry(0, 0, 640, 480) # ステータスバーを表示する self.statusBar() # メニューバーを表示する self.setMenuBar() # グラフを表示する self.setPlot() # ウィンドウを表示する self.show() # setMenuBar()メソッド|メニューバーを生成する def setMenuBar(self): # メニューバーを生成する menubar = self.menuBar() # メニューバーに「ファイル」項目を追加する fileMenu = menubar.addMenu("ファイル") # 「終了」アクションを作成する exitAction = QAction("終了", self) # 「終了」アクションのショートカットを設定する exitAction.setShortcut("Ctrl+Q") # 「終了」アクションのステータスバーのメッセージを設定する exitAction.setStatusTip("プログラムを終了します") # 「終了」アクションとqApp.quit()メソッドを関連付ける exitAction.triggered.connect(qApp.quit) # メニューバーの「ファイル」項目に「終了」アクションを追加する fileMenu.addAction(exitAction) # setPlot()メソッド|グラフを生成する def setPlot(self): # ウィジェットを生成する self.widget = QWidget() # グラフを描画するための「PlotCanvasクラス」のインスタンスを生成する self.canvas = PlotCanvas(self) # 「新規」と「削除」のボタンを作成する self.plot_button = QPushButton("新規グラフ", self) self.clear_button = QPushButton("グラフ削除", self) # 「新規」と「削除」のボタンをPlotCanvasクラスの「plot()」と「clear()」と紐づける self.plot_button.clicked.connect(self.canvas.plot) self.clear_button.clicked.connect(self.canvas.clear) # ウィジェット配置用にレイアウトを生成する main_layout = QGridLayout() # 各ウィジェットをレイアウトに配置する main_layout.addWidget(self.canvas, 0, 0, 1, 5) main_layout.addWidget(self.plot_button, 1, 1, 1, 1) main_layout.addWidget(self.clear_button, 1, 3, 1, 1) # ウィジェットにレイアウトを設定する self.widget.setLayout(main_layout) # ウィジェットをメインウィンドウに追加する self.setCentralWidget(self.widget) # QTimerを初期化する timer = QTimer(self) # timeoutシグナルに「getDateTime()メソッド」をスロットとして指定する timer.timeout.connect(self.getDateTime) # タイマーの動作を開始する timer.start() # getDateTime()メソッド|ステータスバーに現在日時を表示する def getDateTime(self): # 現在の日時を取得する time = datetime.datetime.today() # 取得した日時をフォーマット済み文字列形式に変換する string = time.strftime(u"%Y年%m月%d日 %H時%M分%S秒") # ステータスバーに現在日時を表示する self.statusBar().showMessage(f"現在時刻:{string}") # PlotCanvasクラス|グラフを描画する # グラフ関連の機能を搭載した「FigureCanvasクラス」を継承する class PlotCanvas(FigureCanvas): # コンストラクタ def __init__(self, parent): # 全体の描画領域「Figureオブジェクト」を生成する self.figure = Figure() # グラフの描画領域「Axesオブジェクト」を生成する # 引数は「縦方向に1つ・横方向に1つのプロットを描画し、その1番目のプロットを生成する」という意味で、1つのプロットしか描画しない場合は「111」固定でOK self.axes = self.figure.add_subplot(111) # 親クラスのコンストラクタを呼び出す super(PlotCanvas, self).__init__(self.figure) # 親オブジェクトを設定する self.setParent(parent) # グラフを描画する self.plot() # plot()メソッド|グラフを描画する def plot(self): # -100.0から+100.0の範囲で、25個のランダムな浮動小数点値を生成する self.data = [random.randrange(-100.0, +100.0) for i in range(25)] # グラフを消去する self.axes.cla() # グラフのタイトルを付ける # ここで日本語などのマルチバイト文字を使用すると文字化けするので要注意 self.axes.set_title("Random Graph") # グラフを描画する # 描画形式を「赤色・破線・三角」にする self.axes.plot(self.data, "r--^") # 全体を再描画する self.draw() # clear()メソッド|グラフを消去する def clear(self): # グラフを消去する self.axes.cla() # グラフを再描画する self.draw() # main()メソッド|プログラムのエントリーポイント if __name__ == "__main__": # PyQtを初期化する app = QApplication(sys.argv) # Programクラスのインスタンスを生成する program = Program() # プログラムを終了する sys.exit(app.exec_())
//実行結果
初期状態
更新時
削除時
GUI画面上の「新規グラフ」ボタンをクリックすると、新しいグラフがランダムに描画されます。「グラフ削除」ボタンは、グラフを削除するためのものです。
なお、グラフ描画ライブラリ「Matplotlib」については、以下の記事で詳しく解説しているので、ぜひ参考にしてみてください。
Pythonの「PyQt」を活用すると、高機能かつデザイン性が優れたGUIアプリが作れます。PyQtは現在でもアップデートが続いているモダンなアプリなので、PythonでGUIプログラミングを習得したい場合は、PyQtにチャレンジしてみることをおすすめします。今回ご紹介したウィジェットやテクニックを活用すれば、ハイレベルなGUIアプリを開発できるでしょう。
2024.06.17
子供におすすめのプログラミングスクール10選!学習メリットや教室選びのコツも紹介
#プログラミングスクール
2022.01.06
【完全版】大学生におすすめのプログラミングスクール13選!選ぶコツも詳しく解説
#プログラミングスクール
2024.01.26
【未経験でも転職可】30代におすすめプログラミングスクール8選!
#プログラミングスクール
2024.01.26
初心者必見!独学のJava学習方法とおすすめ本、アプリを詳しく解説
#JAVA
2024.01.26
忙しい社会人におすすめプログラミングスクール15選!失敗しない選び方も詳しく解説
#プログラミングスクール
2022.01.06
【無料あり】大阪のおすすめプログラミングスクール14選!スクール選びのコツも紹介
#プログラミングスクール
2024.01.26
【目的別】東京のおすすめプログラミングスクール20選!スクール選びのコツも徹底解説
#プログラミングスクール
2024.01.26
【無料あり】福岡のおすすめプログラミングスクール13選!選び方も詳しく解説
#プログラミングスクール
2024.01.26
【徹底比較】名古屋のおすすめプログラミングスクール13選!選び方も詳しく解説
#プログラミングスクール
2024.01.26
【徹底比較】おすすめのプログラミングスクール18選!失敗しない選び方も徹底解説
#プログラミングスクール