Python

PythonでPyQtを使ったGUI開発

2021年8月28日

Python PyQt GUI開発

PythonのPyQtを使って実際にGUI開発を行ってみます。

2021年8月現在では、公式サイトにあるPyQtのバージョンが4、5、6と3つのバージョンがダウンロードすることができます。

この記事では、PyQt6を使っています。

PyQtとは

PyQTとは

PyQTとは、クロスプラットフォームなGUIツールキットです。

QtのPythonをバインディングして、GUIプログラミングを行うことができます。

PyQTのインストールについては、こちらの記事をご確認ください。

Python デスクトップアプリ
Pythonでデスクトップアプリの開発!作り方を解説
Pythonでデスクトップアプリを開発するために、TkinterやKivy、PyQt、wxPythonの4つから使いやすいかどうか調べてみました。 アプリケーションの作成するために、ラベルや文字、ボタンの設置はカンタンにできるのか実際に試し ...

続きを見る

GUIについて

GUIとは、Graphical User Interface(グラフィカル ユーザ インターフェース)の略で、ユーザが視覚的に操作しやすいようにします。

GUIは視覚的に操作しますが、反対にCUIというのもあります。

CUIについて

CUIは、Character User Interface(キャラクター ユーザ インターフェース)の略で、コマンドを使った操作になります。

Windowsではコマンドプロンプトを利用したものがCUIにあたります。

メインウインドウを使ってメイン画面の作成

画面レイアウト設定

メイン画面の作成を行います。

タイトルは「マイアプリ」というタイトルで、画面サイズは500 x 400のサイズで作成します。

メイン画面なので、QMainWindowを利用します。

import sys

from PyQt6.QtWidgets import QApplication, QMainWindow

app = QApplication(sys.argv)
main = QMainWindow()

main.setWindowTitle('マイアプリ')
main.resize(500, 400)

main.show()

sys.exit(app.exec())

画面サイズの設定は、9行目のresizeを使っています。

setGeometryを使ってサイズの設定もできますが、アプリケーション実行時の位置も設定しないといけません。

めんどくさいのでresizeで設定することで、アプリケーションの実行されると中央に表示されます(デフォルトが中央表示なんだと思われる)。

あとは、main.showを行うことで画面が表示されます。

PyQt メインウインドウ作成結果

メニューバーの作成

メニュー

ほとんどのアプリケーションでは、メニューバーがあるので実際に作成してみます。

WindowsとMacでメニューの表示でハマったので、その部分についても解説します。

ソースコードは、レイアウト画面作成で利用したコードを使います。

import sys

from PyQt6.QtGui import QAction
from PyQt6.QtWidgets import QApplication, QMainWindow


def newFile():
    print('close')

app = QApplication(sys.argv)
main = QMainWindow()

main.setWindowTitle('マイアプリ')
main.resize(501, 400)


newAct = QAction("&New", main, triggered=newFile)
menuBar = main.menuBar()
fileMenu = menuBar.addMenu("&File")
fileMenu.addAction(newAct)

main.setMenuBar(menuBar)
main.show()

sys.exit(app.exec())

メニューバーを作成するには、QMainWindowにあるmenuBarを呼び出してその中に追加するイメージになります。

18行目からがその処理になります。

menuBar.addMenuを使ってメニューを追加します。

それを元に、addActionを使ってボタンがクリックされた時のアクションをセットします。

Macの場合、このActionをセットしないとメニューにすら表示されない

WindowsとMacの結果は下記なります。

PyQt メニューバー 表示結果
PyQt Mac メニューバー表示結果

WindowsとMacでは、メニューバーの表示の仕方が違います。

Windowsはアプリケーションの中にありますが、Macは画面の上部にあります。

ですがコードに関してはWindowsとMacで分ける様な作りにする必要はないです。

入力関連のパーツ

入力関連パーツ

ラベルや入力項目、ラジオボタン、チェックボックスなどの使い方をここでは試してみます。

紹介するパーツは、下記になります。

パーツ一覧

  • ラベル
  • ライン入力
  • ボタン
  • ラジオボタン
  • チェックボックス

ラベル

ラベルを使うには、QLabelを使います。

setTextを使ってラベルの文字をセットしています。

from PyQt6.QtWidgets import QLabel

label = QLabel()
label.setText('ラベル')

QLabelに直接テキストをセットすることもできます。

from PyQt6.QtWidgets import QLabel

label = QLabel('ラベル')

こっちの方が行数も減って見やすいです。

ラベル表示結果

Enableの設定を行うことができます。

from PyQt6.QtWidgets import QLabel

label = QLabel('ラベル')
label.setEnabled(False)

setEnabledにはTrueまたはFalseを指定することで、テキストの表示が変わります。

今回は、Falseの設定を行っているので灰色で薄くなっています。

ラベル enableの設定

フォントを使うことで、文字のサイズを変更することができます。

from PyQt6.QtGui import QFont
from PyQt6.QtWidgets import QLabel

font = QFont()
font.setPointSize(30)

label = QLabel('ラベル')
label.setFont(font)

フォントのサイズを30に設定しています。

作ったフォントをラベルにセットすることで、反映されます。

ラベル フォントサイズ変更結果

スタイルシートをセットすることで、テキストの色も変更することができます。

from PyQt6.QtWidgets import QLabel

label = QLabel('ラベル')
label.setFont(font)
label.setStyleSheet('QLabel { color: #FFcc55}')

5行目にあるsetStyleSheetでテキストのカラーを変更しています。

ラベルテキストカラー変更

ここで疑問に思ったことがあります。

setStyleSheetでフォントのサイズも設定したらいけるんじゃね?ってことでやってみました。

from PyQt6.QtWidgets import QLabel

label = QLabel('ラベル')
label.setStyleSheet('QLabel { color: #FFcc55; font-size: 50px}')

これを実行してみたら、問題なくフォントのサイズ変わりました。

QColorでカラーの設定ができますが、スタイルシートの理解があればsetStyleSheetの方が断然便利です

Line Edit (1行入力)

テキスト入力などの項目を追加するには、QLineEditを利用します。

HTMLで例えるとinputタグになります。

通常の入力は下記になります。

from PyQt6.QtWidgets import QLineEdit

inputLine = QLineEdit()
通常入力モード

パスワードで入力することもできます。

パスワードモードにするにはsetEchoModeにQLineEdit.EchoMode.Passwordをセットします。

from PyQt6.QtWidgets import QLineEdit

inputLine = QLineEdit()
inputLine.setEchoMode(QLineEdit.EchoMode.Password)
パスワード入力モード

ボタン

ボタンを作成します。

ボタンでは、通常のボタンからトグルボタン、フラットボタンを作成することができます。

ボタンの作成はQPushButtonを使います。

from PyQt6.QtWidgets import QPushButton

btn1 = QPushButton('ボタン')
btn1.setDefault(True)

btn2 = QPushButton('ボタン2')
btn2.setCheckable(True)
btn2.setChecked(True)

btn3 = QPushButton('ボタン3')
btn3.setFlat(True)

setDefaultをTrueにするとボタンが押された状態になります。

ボタン2はトグルボタンになります。

トグルボタンにするには、setCheckableをTrueにする必要があります。

ボタン3がフラットボタンになっており、setFlatでフラットの設定を行います。

ボタン表示1
ボタン表示2

ボタン2はトグルボタンになっているので、1枚目と2枚目でボタンのクリックで表示が変わります。

ラジオボタン

ラジオボタンの作成をします。

ラジオボタンの追加はQRadioButtonを使いますが、単体だとパラメータの取得がめんどくさいのでQButtonGroupも合わせて使います。

from PyQt6.QtWidgets import QButtonGroup, QRadioButton

radioGroup = QButtonGroup()

radioBtn1 = QRadioButton('ラジオ1')
radioBtn2 = QRadioButton('ラジオ2')
radioBtn3 = QRadioButton('ラジオ3')
radioBtn1.setChecked(True)

radioGroup.addButton(radioBtn1, 1)
radioGroup.addButton(radioBtn2, 2)
radioGroup.addButton(radioBtn3, 3)

上記のコードは、QButtonGroupの中にQRadioButtonをセットしています。

setCheckedは、デフォルトでこの値にチェックしているようにしています。

パラメータの取得するのがめんどくさいと言ったのは、10行目からの処理を使うことでカンタンに値を取得することができます。

addButtonで番号を割り振ることで、radioGroupで何にチェックされているか1発で取得できます。

これをしないと、1つ1つradioBtn1からradioBtn3までの値をチェックする必要が出てくるからです。

めんどくさいですよね?ってことです。

ラジオボタンの結果

チェックボックス

チェックボックスの作成を行います。

作成するには、QCheckBoxを利用します。

チェックボックスではQButtonGroupを利用しません。

利用した場合は、複数チェックすることができなくなり1つのチェックになります。

from PyQt6.QtWidgets import QCheckBox

check1 = QCheckBox('チェック1')
check2 = QCheckBox('チェック2')
check3 = QCheckBox('チェック3')

check1.setChecked(True)
check2.setChecked(True)

setCheckedで、チェックの有無を設定します。

チェックボックス表示結果

レイアウト

レイアウト

レイアウトは複数あります。

レイアウトによって、縦に表示したり横に表示したりできます。

他にもグリッドレイアウトを使うことで、細かい配置の設定を行うことも可能です。

基本的なレイアウトは3つになります。

基本レイアウト

  • QBoxLayout
  • QGridLayout
  • QFormLayout

QBoxLayoutの派生クラスとして、QHBoxLayoutとQVBoxLayoutがあります。

この2つが、横に表示したり縦に表示したりするレイアウトです。

MainWindowに直接レイアウトをセットすると下記のエラーが表示されます。

QWidget::setLayout: Attempting to set QLayout "" on QMainWindow "", which already has a layout

これが出ると、一旦Widgetに入れてそれを元にsetCentralWidgetでWidgetをセットしてあげます。

widget = QWidget()
widget.setLayout(layout)

mainWindow.setCertralWidget(widget)

MainWindowではレイアウトではなく、Widgetをセットすることになります。

MainWindowの構造は、ドキュメントをご確認ください。

QHBoxLayout

横並びに表示するレイアウトは、QHBoxLayoutを使います。

インポートする項目は、QtWidgetsのQHBoxLayoutになります。

from PyQt6.QtWidgets import QHBoxLayout, QLabel

layout = QHBoxLayout()
label1 = QLabel('テスト1')
label2 = QLabel('テスト2')
layout.addWidget(label1)
layout.addWidget(label2)

ラベルなどのWidgetをaddWidgetで追加することで横並びに追加されていきます。

横並びレイアウト

QVBoxLayout

縦並びに表示するレイアウトは、QVBoxLayoutを使います。

インポートする項目は、QtWidgetsのQVBoxLayoutになります。

from PyQt6.QtWidgets import QVBoxLayout, QLabel

layout = QVBoxLayout()
label1 = QLabel('テスト1')
label2 = QLabel('テスト2')
layout.addWidget(label1)
layout.addWidget(label2

ラベルなどを追加することで縦に追加されていきます。

縦並びレイアウト

QGridLayout

グリッドレイアウトにするには、QGridLayoutを使います。

QHBoxLayoutやQVBoxLayoutは、addWidgetの時にWidgetを入れるだけでしたが、QGridLayoutは配置も指定する必要があります。

from PyQt6.QtWidgets import QGridLayout, QLabel

layout = QGridLayout()
label1 = QLabel('テスト1')
label2 = QLabel('テスト2')
label3 = QLabel('テスト3')
label4 = QLabel('テスト4')
layout.addWidget(label1, 1, 1)
layout.addWidget(label2, 1, 2)
layout.addWidget(label3, 2, 1)
layout.addWidget(label4, 2, 2)

addWidgetの引数は、セットするWidget、第二引数が行を表、第三引数が列を表します。

なので、上記のラベル1と2が同じ行になり、3と4が同じ行になります。

グリッドレイアウト

QFormLayout

QFormLayoutは2つの列が作成される便利なレイアウトです。

HTMLとかで、ラベルの横に入力フォームがある様なイメージをカンタンに作ることができます。

from PyQt6.QtWidgets import QVBoxLayout, QLabel, QFormLayout

layout = QVBoxLayout()
layout2 = QFormLayout()
layout3 = QFormLayout()
label1 = QLabel('テスト1')
input1 = QLineEdit()
label3 = QLabel('テスト3')
input2 = QLineEdit()

layout2.addRow(label1, input1)
layout3.addRow(label3, input2)

layout.addLayout(layout2)
layout.addLayout(layout3)

QFormLayoutはaddWidgetではなく、addRowを使ってセットしていきます。

このコードは、QFormLayoutを2つ作ってQVBoxLayoutにレイアウトを追加する処理です。

フォームレイアウトの結果表示

まとめ

PyQtを使ったGUI開発を試してみました。

メニューバーの作成や各ラベルやボタン、入力項目、チェックボックスなどパーツの追加についてカンタンに行うことができます。

MainWindowクラスにレイアウトを追加する場合に若干ハマりますが、独自のWindowを作ることで今風のUIとかも全然作れます。

この記事では書くことができなかった、ボタンを押した時のアクション処理や画面遷移については次回以降に書きます。

-Python
-,