台湾出張生活がとうとう一ヶ月経過して、Amazonで購入した30日間のSIMの有効期限が切れてしまった……。
そして週末は基本的にホテルの自室から出ていないので、何もネタが無い。
とうとうSIMが切れると同時に僕の日記のネタが切れてしまった……。
ホテルから出ないので最初の週こそプールに行ってみたが、今じゃ完全なニート。
ニートしながら「ファイナルファンタジー7」と「ドラゴンクエストV 天空の花嫁」で遊んでた。
結婚相手は「フローラ」一択。
もともとフローラ花嫁候補イベントに参加してたのに、迷う理由が全く分からない。浮気じゃん。
花嫁論争が未だ繰り広げられているが、実世界でビアンカのように幼馴染+デボラのような性格な相方を選んだ僕としては、
現実世界を加味しても「フローラ」一択。
ビアンカ派の「ビアンカは山奥の村で独身のまま暮らすから可哀想」とか糞理由じゃん。
自分の人生一度だから!人との為に生きようと思った現実世界はマジつまらん。
「ティファ」「エアリス」論争は、単なるデートだから両方でイイわww
という事で日記を書かずにゲームをしていたので、日記ネタも無くなった。
そうだ!ゲームのように過去の日記をリメイクしたら良いんじゃない?
「FF7」「DQ5」なんて何度リメイクされたことか。デボラとかエメラルドウェポンとか誰やねん。
で、今回はこれ。
半年前にPython3.11が出たばかりの時期に調べた時にはインストールに失敗して幾つかのライブラリは実験できなかった。
おかげで内容も中途半端。
今回は動作させて、EXE化も他のライブラリを試してみる。
※ ネタの導入として書いたが、出張中は土日含めて時間がないのでゲームをしてたのは出張前。
オープンソースソフトウェア(OSS)ライセンス
詳細を語るつもりはないので、ライセンス早見表はこちら。
形態 | ライセンス | 利用者へのコード公開 | 利用物のコード公開 | 改造物のコード公開 | ライセンス明記 | 改造・複製・再配布・商用利用 |
---|---|---|---|---|---|---|
パブリックドメイン | CC0 | 不要 | 不要 | 不要 | 不要 | 可能 |
非コピーレフト | MIT | 不要 | 不要 | 不要 | 必要 | 可能 |
BSD | 不要 | 不要 | 不要 | 必要 | 可能 | |
Apache | 不要 | 不要 | 不要 | 必要 | 可能 | |
準コピーレフト | MPL | 不要 | 不要 | 必要 | 必要 | 可能 |
LGPL | 不要 | 不要 | 必要 | 必要 | 可能 | |
コピーレフト | GPL | 不要 | 必要 | 必要 | 必要 | 可能 |
AGPL | 必要 | 必要 | 必要 | 必要 | 可能 |
商用で使うなら「準コピーレフト」までにしないと開発コード公開が必須となる。
因みにPythonライブラリのライセンスは「pip-licenses」をインストールすれば確認可能。
1 2 3 4 5 6 7 8 9 10 11 |
# # /c/Python311/Scripts/pip install pip-licenses ...インストール # # /c/Python311/Scripts/pip-licenses Name Version License Kivy 2.2.0 MIT License Kivy-Garden 0.1.5 MIT Nuitka 1.5.8 Apache Software License PySide6 6.5.1 GNU Library or Lesser General Public License (LGPL); Other/Proprietary License PySide6-Addons 6.5.1 GNU Library or Lesser General Public License (LGPL); Other/Proprietary License PySide6-Essentials 6.5.1 GNU Library or Lesser General Public License (LGPL); Other/Proprietary License PySimpleGUI 4.60.4 GNU Lesser General Public License v3 or later (LGPLv3+) |
PythonのGUIライブラリ18選
PythonのGUIライブラリは多数ある。
学習用やサンプル的扱いのものも含めて18種類をリスト化した。
ライブラリ | ライセンス | 特徴 |
---|---|---|
TkInter | PSF(標準) | インストール不要、機能が少ない |
CustomTkinter | CC0 1.0 | 手軽さもあり、機能も増えた。レイアウト調整に癖ある |
PyQt | GPL | Qt。多機能でデザインがいい。ライセンスが厳しい |
PySide | LGPL | Qt。多機能でデザインがいい。ライセンスがゆるい |
Kivy | MIT | KV言語で直感的にレイアウトが作れる。モダンデザイン |
WxPython | wxWindows | C++で記述されているため高速 |
Pygame | LGPL | ゲームに特化 |
Flexx | BSD 2-Clause | pythonをjavascript変換してブラウザでGUIを実現 |
pywebview | BSD 3-Clause | htmlでGUIを作成可能 |
PyGTK | LGPL | GNOME desktop環境に最適化 |
PySimpleGUI | LGPLv3+ | コードの書き方がシンプルで直感的でわかりやすい |
turtle | PSF(標準) | 学習用のグラフィックライブラリ |
PyGUI | MIT | 簡単だが機能少なめ |
Flet | Apache License 2.0 | 素早くGUIアプリを作成できる(Webサーバベース) |
WPF | MIT | XAML形式でカスタム性の高いGUI |
Electron | MIT | Node.jsとChromiumを使ったGUI |
Eel | MIT | HTML&CSSを使ってGUIを作れる |
PyOpenGL | OpenGL-ctypes | 2次元/3次元のグラフィックライブラリ |
世界のトレンドはGoogleによると次の通り。
個人的に厳選したライブラリのみ紹介する。
PySide6
世界で人気GUIライブラリの一つである「Qt」をPythonでも使えるようにしたのがPySide6。
PySide2はPython3.11ではインストールに失敗した。
# # /c/Python311/Scripts/pip install PySide2
ERROR: Could not find a version that satisfies the requirement PySide2 (from versions: none)
ERROR: No matching distribution found for PySide2
PySide6はインストール可能。
/c/Python311/Scripts/pip install PySide6
Collecting PySide6
Downloading PySide6-6.5.1-cp37-abi3-win_amd64.whl (7.2 kB)
Collecting shiboken6==6.5.1
Downloading shiboken6-6.5.1-cp37-abi3-win_amd64.whl (1.1 MB)
—————————————- 1.1/1.1 MB 902.8 kB/s eta 0:00:00
PySide2からPySide6への乗り換えはそんなに難しくなさそうだ。
このGUIライブラリは仕事で馴染み深い。
Kivy
kivy特有の言語(kivylang、kivy言語)を用いて、CSSに似たような形でコードを書いていく。
こちらもライブラリのインストールから。
1 2 3 |
/c/Python311/Scripts/pip install kivy Collecting kivy Downloading Kivy-2.2.0-cp311-cp311-win_amd64.whl (4.0 MB) |
wxPython
Python GUIで最初に出会ったライブラリ。
ライブラリのインストールも他と同じ。
1 2 3 |
/c/Python311/Scripts/pip install wxPython Collecting wxPython Downloading wxPython-4.2.0.tar.gz (71.0 MB) |
……だけどインストールに失敗。
1 |
ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory: 'C:\\Users\\hoge\\AppData\\Local\\Temp\\gnupack\\pip-install-bta3tnqd\\wxpython_b019cccefad84721aed3daa870325077\\docs/sphinx/_static/images/inheritance/wx.lib.pubsub.utils.xmltopicdefnprovider.XmlTopicDefnProvider.UnrecognizedSourceFormatError_inheritance.png.map' |
使ってみたいライブラリではないので省略する。
CustomTkinter
GUIライブラリとなるKivyはモダンなデザインで最近のスマホアプリっぽいものが作れたりしますが、kv言語が必要になったりと少しハードルが上がる。
そこで、このライブラリも最近人気。
1 2 3 |
/c/Python311/Scripts/pip install customtkinter Collecting customtkinter Downloading customtkinter-5.1.3-py3-none-any.whl (295 kB) |
GUIもまぁまぁ近代的。
PythonのEXE化ライブラリ3選
Windows上で作成したらEXEファイルとして配布したい。
こちらも幾つもライブラリがある。
ライブラリ | ライセンス | 特徴 |
---|---|---|
PyInstaller | GPL 2.0 | ファイルサイズがデカい・起動が遅い・ウイルス判定されやすい |
py2exe | MPL2 | Windows 専用 |
Nuitka | Apache Software License | Python コードを一度C言語にトランスパイルしgccでコンパイルする |
ライセンスと速度を加味して「Nuitka」を使ってみる。
1 2 3 |
# # /c/Python311/Scripts/pip install nuitka zstandard Collecting nuitka Downloading Nuitka-1.5.8.tar.gz (4.2 MB) |
EXEファイル作成方法は次のような形になる。
1 |
/c/Python311/Scripts/nuitka.bat --mingw64 --follow-imports --onefile kivy_ui.py |
100行未満もサンプルコードでも「10分」程度はEXE作成時間が必要だった。
コンソール表示を隠して、プラグインを有効化にしたり……と実際のオプションはもっと長くなるはずだ。
1 |
/c/Python311/Scripts/nuitka.bat --mingw64 --follow-imports --onefile --enable-plugin=tk-inter --disable-console pysimple.py |
PyInstallerでTkInter で作ったEXEファイルは「9MB」だったけど、「8MB」となた。
PyInstallerでPySimpleGUI で作ったEXEファイルは「60MB」だったけど、「38MB」となった。
ファイルサイズが小さくなっている事は確認できた。速度はよく分からない。
おわりに
この手のライブラリはどんどん増えるし、何を使ったらやりたい事を実現できるのか?応用が効くのか分からない。
そして、せっかく学習しても転職先や移動先で使っているライブラリが違ったら悲惨なので、できる限りシェアが大きなライブラリを使いたい。
調査は継続する。
ソースコード
単なるネットに転がっているサンプルコード。
CustomTkinter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
import customtkinter import tkinter class App(customtkinter.CTk): def __init__(self): super().__init__() self.title("テスト") self.minsize(400, 300) self.entry = customtkinter.CTkEntry(master=self, placeholder_text="ここにテキストを入力", width=300, height=25, border_width=2, corner_radius=10) self.entry.pack(padx=20, pady=20) self.button = customtkinter.CTkButton(master=self, width=300, height=50, border_width=0, corner_radius=10, text="ボタン", command=self.button_callback) self.button.pack(padx=20, pady=20) self.text_var = tkinter.StringVar(value="入力されたテストを表示") self.label = customtkinter.CTkLabel(master=self, textvariable=self.text_var, width=120, height=25, corner_radius=8) self.label.pack(padx=20, pady=20) def button_callback(self): self.label_get = self.entry.get() self.text_var.set(self.label_get) if __name__ == "__main__": app = App() app.mainloop() |
PySide6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
import sys from PySide6.QtWidgets import ( QApplication, QCheckBox, QComboBox, QDateEdit, QDateTimeEdit, QDial, QDoubleSpinBox, QFontComboBox, QLabel, QLCDNumber, QLineEdit, QMainWindow, QProgressBar, QPushButton, QRadioButton, QSlider, QSpinBox, QTimeEdit, QVBoxLayout, QWidget, ) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("My App") layout = QVBoxLayout() widgets = [ QCheckBox, QComboBox, QDateEdit, QDateTimeEdit, QDial, QDoubleSpinBox, QFontComboBox, QLCDNumber, QLabel, QLineEdit, QProgressBar, QPushButton, QRadioButton, QSlider, QSpinBox, QTimeEdit, ] for widget in widgets: layout.addWidget(widget()) central_widget = QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec() |
Kivy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
from kivy.app import App from kivy.uix.label import Label from kivy.uix.textinput import TextInput from kivy.uix.gridlayout import GridLayout from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.core.window import Window class KivyApp(App): def build(self): self.title = "Login Screen" Window.size = (400,200) layout = GridLayout(cols=2,rows=2,padding=10,spacing=10,row_default_height=30) usernameinput = TextInput() passwordinput = TextInput(password=True) usernamelbl = Label(text="Username",size_hint_x=None, width=100) passwordlbl = Label(text="Password",size_hint_x=None, width=100) layout.add_widget(usernamelbl) layout.add_widget(usernameinput) layout.add_widget(passwordlbl) layout.add_widget(passwordinput) main_layout = BoxLayout(orientation='vertical',padding=10,spacing=10) main_layout.add_widget(layout) loginbutton = Button(text="Login") main_layout.add_widget(loginbutton) return main_layout if __name__ == '__main__': app = KivyApp() app.run() |