プロジェクト

全般

プロフィール

Python GUIライブラリ各種

PythonでGUIは可能か

実はPythonには標準ライブラリで、Tkinterが提供されています。 Tcl/TkのPythonバインディングです。少し癖がありますが、Tcl/Tkに馴染みがあれば理解が容易でしょう。
標準以外にも多数のGUIライブラリが存在します。

いろいろなPython GUIライブラリ

ここでは、いろいろなPythonのGUIライブラリのざっくり概要と、ボタンをクリックするとあいさつ文を表示するごく簡単な画面を持つプログラムを書いて比較します。

Tkinter

Python Tkinter

ごく基本的なウィジェットと、3種類のレイアウト(ジオメトリマネージャ)があります。

ウィジェットは、Label、Entry(1行テキスト入力)、Message(複数行テキスト入力)、Button、RadioButton、CheckButton、ListBox、Scrollbar、Scale、MenuButton、Text、Spinbox、Frame、LabelFrame、PanedWindow、Bitmap、Canvasなどです。

レイアウトは次の3種があります。

  • Placer
    絶対座標指定でウィジェットを配置
  • Packer
    ウィンドウにウィジェットを詰め込む
  • Gridder
    ウィジェットを格子状に配置

GUI処理のイベントループは、Tkクラスのmainloopメソッドを実行します。

Hello, world
from tkinter import Tk, Frame, Button, Label

class Application(Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.label = Label(master)
        self.label.pack()
        button = Button(
            master, text='ご挨拶',
            command=lambda: self.label.configure(text='Hello, world.')
        )
        button.pack()

if __name__ == "__main__":
    root = Tk()
    app = Application(master=root)
    app.mainloop()

  • Tk()でトップレベルウィンドウを生成
  • Frame派生のApplicationクラスを定義
    • Labelを生成、テキストは空
    • Buttonを生成、ボタンに表示するテキスト、ボタンが押された際の処理を定義
  • mainloop実行

Kivi

ライセンス MIT

画面の記述をPythonコードだけでなく、Kv言語で記述することができます。

レイアウトは、AnchorLayout、BoxLayout、FloatLayout、RelativeLayout、GridLayout、PageLayout、ScatterLayout、StackLayoutがあります。

標準では日本語が文字化けします。

hello world (Pythonコードのみで記述)
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout

class HelloScreen(BoxLayout):
    def __init__(self):
        super().__init__()
        self.orientation = 'vertical'
        self.label = Label()
        self.add_widget(self.label)
        self.button = Button(text='Greeting')
        self.button.bind(on_press=self.handle_greeting)
        self.add_widget(self.button)

    def handle_greeting(self, event):
        self.label.text = 'Hello, world.'

class HelloApp(App):    # GUIアプリケーションクラスを定義
    def build(self):
        return HelloScreen()

if __name__ == '__main__':
    HelloApp().run()
  • Appを派生しGUIアプリケーションクラスHelloAppを定義、buildメソッドはウィンドウ内のトップウィジェットを生成し返却する
  • トップレベルウィジェットはBoxLayoutを派生したHelloScreenクラスを定義
    • 配置を垂直方向(vertical)と指定
    • LabelとButtonを生成
    • Buttonがクリックされたときは、メソッドhandle_greetingを呼ぶよう紐づけ
  • イベントループは、App派生クラスのrunメソッドを呼ぶ
hello world (PythonとKv言語で記述)
  • hello_app.py
    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.properties import StringProperty
    
    class HelloScreen(Widget):
        text = StringProperty('')
    
        def on_button_click(self):
            self.text = 'Hello, world.'
    
    class HelloApp(App):
        def build(self):
            return HelloScreen()
    
    if __name__ == '__main__':
        HelloApp().run()
    
  • hello.kv
    <HelloScreen>:
        BoxLayout:
            orientation: 'vertical'
    
            Label:
                id: label
                text: root.text
    
            Button:
                id: button
                text: "Greeting" 
                on_press: root.on_button_click()
    
  • HelloAppからAppを除いた Helloを小文字にした hello.kvが自動で読み込まれます
  • hello.kvに記述した<HelloScreen>の名前と同じクラスがレイアウト定義の対象となります
  • Labelのtextは、root(HelloScreenクラス)の text(StringProperty)にバインディングします
  • Buttonが押されたイベント(on_press)は、root(HelloScreenクラス)のon_button_clickメソッドにバインディングします
PyCharmでKvファイル編集

market placeにはプラグインがアップされていませんが、以下からKV Lang File Type Support設定(PyCharm_kv_completion.jar)をダウンロードし、[File]メニュー > [Manage IDE Settings] > [Import Settings]で読み込むと、Kvファイルの編集サポートが利用できます。
https://github.com/Zen-CODE/kivybits/tree/master/IDE

PySimple

ライセンス LGPL

レイアウトは、上から下へ詰める単純なものです。入れ子のlistで上から下へと、左右方向にウィジェットの配置を指定します。
コード量が少なくGUIを記述できるとされています。

ウィジェットは、Text、Image、InputText、Multiline、Button、CheckBox、Radio、Listbox、Spin、Slider、Frame、VerticalSeparator、ProgressBar、Table、Tree、OptionMenu、Menubar、Canvas、PopupGetText、などです。
レイアウトは、Tab、Pane、Columnなどです。

Hello world
import PySimpleGUI as sg

class Application:
    KEY_CLICK_GREET = '-GREET-'    # ボタンを押した際のイベント定義
    KEY_GREETING = '-GREETING-'    # あいさつ文表示ウィジェットのユニークID

    def __init__(self):
        self.text = sg.Text(key=self.KEY_GREETING)                    # あいさつ文表示ウィジェットTextを生成
        self.button = sg.Button('ご挨拶', key=self.KEY_CLICK_GREET)   # ボタンウィジェットを生成
        self.layout = [[self.text], [self.button]]                    # レイアウト定義(上下にTextとButton)
        self.window = sg.Window('Hello App', self.layout)             # トップレベルウィンドウを生成、タイトルとレイアウトを指定

    def start(self):
        while True:                                                     # イベントループ
            event, values = self.window.read()                          # トップレベルウィンドウの中でイベントを待ち、イベントが発生すると復帰
            if event == sg.WIN_CLOSED:                                  # イベントがWIN_CLOSEならイベントループを抜ける
                break
            if event == self.KEY_CLICK_GREET:                           # イベントがボタン押下(KEY_GREET)ならあいさつ文表示ウィジェットに文字列をセット
                self.window[self.KEY_GREETING].Update('Hello, world.')
        self.window.close()

if __name__ == '__main__':
    application = Application()
    application.start()
  • レイアウト定義は、多次元リストで上下左右に配置できるので割とシンプルです
  • イベントループは自前で記述するので少々大変(柔軟性が高い?)
  • イベントループの中で、イベント発生源の識別、操作対象ウィジェットの識別にユニークなIDを定義し使用する必要があり、煩雑