Pythonでも王道のPyQt, PySide6がいい。PySimpleGUIは罠だらけ
PythonでGUIアプリの開発の話。2周回って再びPySide6に戻ってきた。そう、最初にPythonでGUIをどのライブラリで実装しようか検討した際に最初に結論を出したときの決定候補、PySide6だったのだ。これがなぜかPySimpleGUIが出てきて色々混乱し、結局検討候補を全部試した結果、2周回ってPySide6に戻ってきた、という無駄な周回をした日記。
(約 5,400文字の記事です。)
シンプルに見えて実はドロドロなPySimpleGUI
最初にPySide6に決めてみたものの、公式チュートリアルサイトを覗いて何だか色々面倒そうだな、と思って考え改めたのが運の尽き。PySimpleGUIは確かに「単に実装するだけ」ならば驚速だった。だがしかし!肝心のUIとしての使い勝手が悪かった。悪すぎた。
本当にもう、ボタンUIとウィンドウを設置すること「しか」できなかったのだ😭例えばシンプルに、Windowsに慣れた人ならば誰でも考える、矢印キーによるボタン選択とEnterキーによるボタン押下、たったこれだけの基本機能が、PySimpleGUIでは「そのままでは」できなかったのだ。
話は前後するが、例えば以下はPySide6でごく普通に実装しただけ。そしてごく普通に動く。
たったこれだけのことがなぜかPySimpleGUIでは普通に実装できないのだ。
PySimpleGUIでは
矢印キーでフォーカスが動いてくれない(工夫の実装が必要)
Enterキーでボタンを押下できない(工夫の実装が必要)
Tkinter 8.6.10以降の仕様変更でフォーカスの初期位置がなし(ユーザーはTABキー1回押しが必須)
フォーカスの位置がないので上動画のようにApplyなどの任意のボタンをデフォルトにできない(PySimpleGUI上でのdefault=Trueが無視される)
昨日一日かけてPySimpleGUIの仕様周りを眺めたりGoogle検索したりしてみたが、涙ぐましいほどの努力をしない限りPySimpleGUIで上記を実現できない。Windowsアプリ開発環境ならサクッと実装されるはずの、ごく普通の基本機能。これがPySimpleGUIにはない。
そう、PySimpleGUIは実装もシンプルだが「ボタンやウィンドウUI」もまたシンプルだったのだ。ボタンとウィンドウ以外のことが何もできなかったのだ。なので当然以下も厳しい。
ボタンにホットキーの設定が難しい
Alt + アルファベットキーでの操作も難しい
要するにPySimpleGUIではキーボードでGUIを操作できない
これが最大の罠だった。実装がシンプルだったが、GUIでユーザーがやれることもまたシンプルだった。要するにボタンや要素をマウス操作できるだけ。キーボードからの操作は絶望的。
キーボード操作できないPySimpleGUIの弱点
玄人向けのアプリを作れない。つまりはプロ向けアプリは作れない。プロは忙しい。秒単位で削れるものを削りたいのだ。なのでたかだかOKダイアログくらいはEnterキーでぽーんと閉じたいわけ。
そして最大の問題点、私が、そう、私がキーボード操作でOKボタンやYes/Noボタンを、キーボードで操作したいのだ!それができないPySimpleGUI、もういきなりストレスMaxである。開発する気力すら失せたわ!💢
PySimpleGUIは中途半端
GUIとしての基本機能があまりにもショボすぎた。「え?そんなこともできないの?」があまりにも多いのだ。本当に、ウィンドウとボタン類を設置できるだけ。操作方法はマウス操作オンリーでキーボード操作は悲しいほどにできない。そしてメチャクチャ努力すればようやくキーボード操作が実現できる。実装がシンプルでも使用感を「普通にするための多大な努力」が必要なのがPySimpleGUI。もはや本末転倒😭
結局、GUIは老舗のQt系に限る
これな!私も1週間前に自分で決めていたのに、UpNoteにもたくさんメモを残していたのに、ドウシテコウナッタ……。
結局腹をくくってQt系、PySide6の公式サイトをじっくり読みながらPyCharmに打ち込んでみたら、まぁ普通に動いたわけで。
以下の私の、ごく普通のユーザーが期待することは何も工夫しなくても実現されたわけで。
既定ボタンにフォーカスがある状態でウィンドウが開く(今回はApply指定)
上下左右の矢印キーでフォーカスが動く
(Yes/No系ダイアログでは)Enterキーでボタンを押下できる(動画にはないがコンソールにボタン種類がprintされています)
そう、たったこれだけを、ごく普通の実装で実現できたのだ。これがQt系の実力だ。
TkinterとQt系は根幹が違う。それが原因
TkinterはPythonのライブラリ。だがPython専用ではなくていにしえの言語TclをGUIで扱うために生まれたツール、それがTkinter。なのでクロスプラットフォーム対応だが逆に言うとGUIへのチューニングはかなり古く、イマドキのOSのGUIにはチューニングが「されていない」まま現在に至る。
それに対してQt系は根っこはC++だったかな?とにかくGUIにこだわり続けていく数年というベテラン勢・実績多数のフレームワークだ。
ライブラリとフレームワーク、この差が今回の差に繋がった。
結局は「GUIと向き合っている時間が長いQt」によるGUIへの利便性の勝利というわけだ。GUI操作について当たり前のことが当たり前にできることを保証してくれるのがQtである以上、作法はQtに従うべきだし、その対価として「ごく普通のGUIの使い心地」を実装できるわけだ。
GUIに何を求めるかが答え
なので実はPySimpleGUIとPySide6では、1つのGUIにしても求めるものとその深さが違った。PySimpleGUIは「とにかくボタンUIをマウスで操作できればそれ以外はなしで」というシンプルなスタイル。今回見落としたのは「まさかキーボード操作までバッサリカット」だとは思いもしなかった点だ。
それに対してQtは実装はQt流の作法に従わざるを得ないが(ゆえにフレームワークなのだが)、それに従う限りGUIでできることはほぼ何でも制限無く実装可能というわけだ。
私が真にGUIに求めていたものは「ごく普通のGUIの挙動」だったので、PySimpleGUIはあまりにもシンプル過ぎた。そして天井が低すぎたのだ。行き詰まってその解決策をネットの海から探し出す労力があったら、最初からコツコツとQt流のフレームワークを体得したほうが「急がば回れ」になるわけだ。今回のPySimpleGUIの「矢印キーとEnterキー操作」でよく分かった。身にしみた。
なので時間はかかるかも知れないが、Pythonで私が求めるGUIはQt系が答えだった。そしてライセンスの関係上、PyQtではなくてPySide6でなくてはならない、自分的に。
結局、1週間前の答えに戻ってきただけ。何という無駄な労力。いや、決して無駄ではなかったのだけれど、空回りした気がする。
最後に腹いせ?というか恨み節というか、ここまでの経験で思ったトゲのある感想をば。
Tkinter、標準ライブラリにあるってだけで、他にメリットがない。PythonでもGUIを実装できるよ、という言い訳のためにだけに存在する?ボタン類はマウス操作とTAB, Space以外は基本的には受け付けない仕様 (8.6.9以降)。GUIは嘘ではないが、キーボードユーザーにとっては「それはGUIではない」というくらい、原始的GUIしか実現できない。
PySimpleGUI、なんだかものすごく「シンプルにできる!」を強調しているが大風呂敷が過ぎる。結局思い通りのGUIを作ろうとすると「あれが足りない、これが足りない」となって、結局はごちゃごちゃと実装する羽目になる。そしてその情報収集とトライ&エラーの時間の無駄さ加減が半端ない。
PySimpleGUI、実はTkinterやQt系のラッパーに過ぎない。張り子の虎、虎の威を借る狐かな。最終的には大元の制限を受けることになる。
PySimpleGUIって結局、「そのまんまポン付け」する場合しかシンプルにならない。レールから外れると全然シンプルじゃなくなる。
PySimpleGUI、ドキュメントと導入は親切丁寧だが、その後のユーザーサポートや機能拡張についてのリクエストや提案については途端に冷徹で突き放している。開発者が忙しいのは分かるが、何だか100年の愛も冷めた。それでいてやっていることはラッパーという……。有料化してもそれとはちょっと、これは如何に?
PyQt, PySide6などのQt系、公式ドキュメントが中級者過ぎる。もっと分かりやすく導入部分を作れると思うのだが、そこが惜しい。簡単なUIならば割と簡単に実装できるのに、入り口がやたらと豪華な門みたいで、一見さんはビビる。
だがQt系はGUIで実現できることはほぼほぼ実装可能。フレームワークなのでQt流の作法を強要されるがそれに従えば平和。洗練された仕組みゆえのフレームワークなのだと実感できる。習うより慣れろを地で行くスタイル。
Pythonでアプリ開発するならPySide6一択
PyQtで学んでもいいが、商用アプリを作るならライセンスの関係でL GPL v3.0を使えるPySide6一択だと思う。なので私はPySide6でコツコツGUIを学ぶことにした。まぁ急ぐ内容もないが😅そして今回試してみたが、シンプルなYes/Noなどのポップアップウィンドウくらいならば大してソースコードもそんなにごちゃごちゃしていない。(これはどうやらPySimpleGUIの作者の言い分に騙されたかな、という感がある。)
以下、確かにぱっと見では「長いな」と思うが、内容をよく見れば、中段がボタンUIの改行列記、後半が単なるIf分の列記で行数が膨らんでいるだけ。
import sys
from PySide6.QtWidgets import QApplication, QMessageBox
if __name__ == '__main__':
app = QApplication(sys.argv)
while True:
ret = QMessageBox.information(
None,
"My message",
"Press a button!",
buttons=QMessageBox.Apply | QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel,
defaultButton=QMessageBox.Apply
)
if ret == QMessageBox.Yes:
print('Yes was clicked')
elif ret == QMessageBox.No:
print('No was clicked')
elif ret == QMessageBox.Apply:
print('Apply was clicked')
elif ret == QMessageBox.Cancel:
print('Cancel was clicked')
break
中身は結局は、
何だか色々必要な呪文の宣言
ウィンドウやボタン類のセット
ボタンを押したらどうなるかをセット
この3つしかない。行数で考えるのではなくて「意味のブロック」で見れば、なぁんだ、大したことをしていないじゃないか!これで「複雑だ!」というのではればプログラミングは向いていない。というか詭弁な気もする。PySimpleGUI作者に丸め込まれた自分……。
3日間を溶かした上に、また深夜のnote更新だ。もういい加減朝型に戻したい。
今回の創作活動は約1時間30分(累積 約3,850時間)
(1,101回目のnote更新)