📖

Python GUIライブラリ比較

に公開1

はじめに

「PythonでGUIを作りたい」と思ったとき、選択肢が多すぎて迷うことはありませんか?
本記事では、古典的な標準ライブラリから、モダンなモバイル向けフレームワークまで、主要な4つのライブラリを「同じ機能のアプリを作る」という条件で比較します。
GUIライブラリの選択をする際に、参考になれば幸いです。

比較するGUIライブラリ

サンプル概要

本記事で作成するサンプルの機能は、以下になります。

  • ウィンドウ作成・タイトルを指定
  • テキスト入力欄(Entry)作成
  • ボタン作成
  • ボタン押下 → 入力したテキストをポップアップ表示(alert的)

理由は、以下になります。

  • GUIの基本要素(Window / Input / Event / Dialog)を網羅している
  • ロジックがほぼ共通だが、GUIライブラリごとの差が出やすい
  • コード量が増えすぎない

実装例

1.Tkinter

Tkinter は Python 標準ライブラリに含まれているGUIライブラリで、追加インストール不要で利用できるのが特徴です。

実際のコード

import tkinter as tk  # Tkinterライブラリを「tk」という名前でインポート(GUI作成用)
from tkinter import messagebox  # ダイアログボックスを表示するためのサブモジュールをインポート

# ボタンがクリックされた時に実行される関数(イベントハンドラ)の定義
def show_message():
    # エントリー(入力欄)に入力されている文字列を取得して変数 text に代入
    text = entry.get()
    # メッセージボックスを表示。第一引数がタイトル、第二引数が本文
    messagebox.showinfo("入力内容", text)

# メインウィンドウ(土台となる画面)を作成
root = tk.Tk()
# ウィンドウ上部のタイトルバーに表示されるテキストを設定
root.title("Tkinter サンプルアプリ")
# ウィンドウの初期サイズを指定(幅400px × 高さ200px)
root.geometry("400x200")

# --- 画面パーツ(ウィジェット)の配置 ---

# ラベル作成:画面に文字を表示するためのパーツ
label = tk.Label(root, text="メッセージを入力してください")
# ラベルを画面に配置。padyは「上下の隙間(パディング)」を10px空ける指定
label.pack(pady=10)

# テキスト入力欄(エントリー)作成:ユーザーが文字を打つためのパーツ。幅を40文字分に設定
entry = tk.Entry(root, width=40)
# 入力欄を画面に配置。上下に5pxの隙間を空ける
entry.pack(pady=5)

# ボタン作成:クリックで動作するパーツ。commandでクリック時に呼び出す関数を指定
button = tk.Button(root, text="表示する", command=show_message)
# ボタンを画面に配置。上下に20pxの隙間を空ける
button.pack(pady=20)

# メインループ開始:ウィンドウを表示し続け、ユーザーの操作(クリックなど)を待機する状態にする
# これを書かないと、プログラムは一瞬で終了してしまいます
root.mainloop()

表示

ポイント

  • 追加インストール不要
  • コード量が少ない
  • 見た目はやや素朴
  • 業務ツール用途なら十分実用的

2.PySide

PySide(Qt)は、Tkinterと比べるとコード量はやや増えるものの、レイアウト管理やウィジェット構成が明確で、業務アプリケーションとしては扱いやすい印象を受けました。
見た目も比較的整っており、中〜大規模なGUIアプリに向いていそうです。

インストール

pysideをはじめて使う際は、インストールが必要です。
PySide6 が主流なので、今回はそれでいきます。

pip install pyside6

実際のコード

import sys  # システム固有のパラメータや関数(コマンドライン引数など)を扱うための標準ライブラリ
from PySide6.QtWidgets import (
    QApplication,  # GUIアプリケーション全体を管理するクラス
    QWidget,       # すべてのユーザーインターフェースオブジェクトの基本クラス(ウィンドウ)
    QLabel,        # テキストを表示するためのラベル
    QLineEdit,     # 1行のテキスト入力フィールド
    QPushButton,   # クリック可能なボタン
    QVBoxLayout,   # ウィジェットを垂直方向に並べるレイアウトマネージャー
    QMessageBox    # メッセージボックス(ポップアップ)を表示するためのクラス
)

# ボタンがクリックされた時に実行される関数(スロット)
def show_message():
    # 入力フィールド(entry)から現在入力されている文字列を取得
    text = entry.text()
    # メッセージボックスを表示(親ウィンドウ, タイトル, 表示するテキスト)
    QMessageBox.information(window, "入力内容", text)

# --- アプリケーションの基盤準備 ---
# アプリケーション全体を管理するインスタンスを作成。sys.argv は実行時の引数を渡します。
app = QApplication(sys.argv)

# --- メインウィンドウの設定 ---
# ウィンドウの土台となるウィジェットを作成
window = QWidget()
# ウィンドウ上部のタイトルバーに表示されるテキストを設定
window.setWindowTitle("PySide サンプルアプリ")
# ウィンドウの初期サイズを設定(幅400ピクセル、高さ100ピクセル)
window.resize(400, 100)

# --- 画面パーツ(ウィジェット)の作成 ---
label = QLabel("メッセージを入力してください")  # 説明文のラベル
entry = QLineEdit()                         # 文字入力欄
button = QPushButton("表示する")              # 実行ボタン

# --- イベント(動作)の紐付け ---
# ボタンが「クリックされた(clicked)」ら「show_message関数を呼び出す(connect)」ように設定
button.clicked.connect(show_message)

# --- レイアウト(配置)の設定 ---
# パーツを縦に並べるためのレイアウトを作成
layout = QVBoxLayout()
layout.addWidget(label)   # ラベルをレイアウトに追加
layout.addWidget(entry)   # 入力欄をレイアウトに追加
layout.addWidget(button)  # ボタンをレイアウトに追加

# window(土台)に作成したレイアウトを適用する
window.setLayout(layout)
# ウィンドウを画面に表示する
window.show()

# --- アプリケーションの実行 ---
# イベントループ(クリック待ちなどの状態)を開始。
# アプリが終了したら、その終了コードを sys.exit に渡してプログラムを安全に終了させる。
sys.exit(app.exec())

表示

ポイント

  • Tkinterより 見た目が少しモダン
  • ダイアログが OSネイティブに近い
  • フォントや余白が自然

3.wxPython

wxPythonは、各OSのネイティブウィジェットを利用しているため、見た目が非常に自然で、業務アプリとの相性が良いと感じました。
一方で、レイアウトやイベント処理はやや記述量が多く、最初は少し慣れが必要そうです。

インストール

wxPythonをはじめて使う際は、インストールが必要です。

pip install wxPython

実際のコード

import wx  # wxPythonライブラリをインポート

# メインウィンドウ(フレーム)を定義するクラス
class SampleFrame(wx.Frame):
    def __init__(self):
        # 親クラス(wx.Frame)を初期化:親なし(None)、タイトル、ウィンドウサイズを指定
        super().__init__(None, title="wxPython サンプルアプリ", size=(400, 180))

        # ウィジェットを配置するための土台(パネル)を作成
        panel = wx.Panel(self)

        # --- ウィジェット作成 ---
        # 静的テキスト(ラベル)を作成
        label = wx.StaticText(panel, label="メッセージを入力してください")
        # テキスト入力ボックスを作成(他のメソッドでも使うので self. を付けて保持)
        self.text_ctrl = wx.TextCtrl(panel)
        # 実行ボタンを作成
        button = wx.Button(panel, label="表示する")

        # --- イベント設定 ---
        # ボタンが押されたとき(wx.EVT_BUTTON)に、self.on_clickメソッドを呼び出すよう紐付け
        button.Bind(wx.EVT_BUTTON, self.on_click)

        # --- レイアウト(縦配置) ---
        # ウィジェットを自動整列させるための「Sizer」を作成(垂直方向に並べる設定)
        sizer = wx.BoxSizer(wx.VERTICAL)
        # ラベルを追加:余白(10px)を全方向に設定
        sizer.Add(label, 0, wx.ALL, 10)
        # 入力ボックスを追加:左右に10pxの余白、横幅いっぱい(EXPAND)に広げる
        sizer.Add(self.text_ctrl, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
        # ボタンを追加:上下左右に20pxの余白、中央揃え(ALIGN_CENTER)に配置
        sizer.Add(button, 0, wx.ALL | wx.ALIGN_CENTER, 20)

        # パネルにこのレイアウト(Sizer)を適用
        panel.SetSizer(sizer)

        # ウィンドウを表示状態にする
        self.Show()

    # ボタンがクリックされた時の処理
    def on_click(self, event):
        # 入力ボックスから文字列を取得
        text = self.text_ctrl.GetValue()
        # メッセージボックスを表示(内容, タイトル, OKボタン+情報アイコン)
        wx.MessageBox(text, "入力内容", wx.OK | wx.ICON_INFORMATION)

# アプリケーション全体を管理するクラス
class SampleApp(wx.App):
    def OnInit(self):
        # メインウィンドウのインスタンスを作成
        frame = SampleFrame()
        # ウィンドウを表示
        frame.Show()
        # アプリの初期化が成功したことを示すためにTrueを返す
        return True

# スクリプトが直接実行された場合の処理
if __name__ == "__main__":
    # アプリケーションのインスタンスを作成
    app = SampleApp()
    # イベント待ち受けループを開始(プログラムを終了させずに待機させる)
    app.MainLoop()

表示

ポイント

  • ボタン・ダイアログが OS標準そのもの
  • フォントや余白が自然
  • 業務ツール感が強い

4.Kivy

Kivyは、これまでのGUIライブラリとは設計思想が大きく異なり、OSネイティブな業務ツールというより、モバイルやタッチ操作を意識した UI フレームワークという印象を受けました。
一方で、レイアウトの柔軟性は高く、見た目を重視するアプリには向いていそうです。

インストール

Kivy をはじめて使う際は、インストールが必要です。

pip install kivy

また、日本語を使用する場合はフォントファイルの読み込みが必要になります。
サンプルで使用しているフォントは Noto Sans Japanese は以下からダウンロードできます。
https://fonts.google.com/noto/specimen/Noto+Sans+JP

実際のコード

# Kivyの基本機能をインポート
from kivy.app import App  # アプリの基盤となるクラス
from kivy.uix.boxlayout import BoxLayout  # ウィジェットを並べるレイアウト
from kivy.uix.label import Label  # テキストを表示するラベル
from kivy.uix.textinput import TextInput  # 文字入力欄
from kivy.uix.button import Button  # クリック可能なボタン
from kivy.uix.popup import Popup  # ポップアップウィンドウ
from kivy.core.window import Window  # ウィンドウ自体の設定(色やサイズ)
from kivy.core.text import LabelBase  # 日本語フォントなどを登録する機能

# --- 日本語フォントの設定 ---
# デフォルトでは日本語が文字化けするため、外部フォントを"JP"という名前で登録
LabelBase.register(
    name="JP",
    fn_regular="NotoSansJP-VariableFont_wght.ttf" 
)

# --- ウィンドウ全体の見た目 ---
Window.clearcolor = (0.2, 0.2, 0.2, 1)  # 背景色を濃いグレーに設定 (R, G, B, A)
Window.size = (400, 300)                # 起動時のウィンドウ幅400px、高さ300px

# --- アプリのメインロジック ---
class SampleApp(App):
    def build(self):
        # アプリウィンドウのタイトル
        self.title = "Kivy サンプルアプリ"

        # レイアウトの作成:垂直(vertical)にウィジェットを並べる箱
        layout = BoxLayout(
            orientation="vertical", # 子要素を縦に並べる
            padding=40,             # 箱の内側の余白(上下左右)
            spacing=20              # ウィジェット同士の隙間
        )

        # テキストを表示する「ラベル」の設定
        label = Label(
            text="メッセージを入力してください",
            font_name="JP",         # 登録した日本語フォントを使用
            color=(1, 1, 1, 1),      # 文字色(白)
            font_size=16,           # 文字サイズ
            size_hint_y=None,       # 高さを自動調整せず固定にするためのフラグ
            height=30               # 高さを30pxに指定
        )

        # 文字を入力する「テキストボックス」の設定
        text_input = TextInput(
            multiline=False,        # 改行を許可しない(1行入力)
            font_name="JP",
            font_size=14,
            size_hint_y=None,       # 高さを固定
            height=40,
            padding=[10, 10]        # 入力枠内のテキストの余白
        )

        # クリックするための「ボタン」の設定
        button = Button(
            text="表示する",
            font_name="JP",
            font_size=18,
            size_hint_y=None,
            height=50,
            background_color=(0.1, 0.5, 0.8, 1) # ボタンの背景色(青系)
        )

        # 余白を埋めるためのスペーサー(空のウィジェット)
        # これを最後に追加することで、上の3つが上に詰められる
        from kivy.uix.widget import Widget
        spacer = Widget() 

        # ボタンが押されたときに実行される関数(イベントハンドラ)
        def show_message(instance):
            # 新しいウィンドウ(ポップアップ)を作成
            popup = Popup(
                title="入力内容",
                title_font="JP",
                content=Label(
                    text=text_input.text, # テキストボックスの内容を表示
                    font_name="JP",
                    color=(1, 1, 1, 1)
                ),
                size_hint=(0.7, 0.3)      # 画面全体に対する幅70%、高さ30%のサイズ
            )
            popup.open() # ポップアップを表示

        # ボタンと関数を紐づける(クリックされたら show_message を呼ぶ)
        button.bind(on_press=show_message)

        # 作成した各部品をレイアウト(BoxLayout)に追加
        layout.add_widget(label)      # 1番上:ラベル
        layout.add_widget(text_input) # 2番目:入力欄
        layout.add_widget(button)     # 3番目:ボタン
        layout.add_widget(spacer)     # 4番目:残りの空間を埋めるための空要素

        return layout # 設定したレイアウトをアプリの画面として返す

# プログラムの開始点
if __name__ == "__main__":
    SampleApp().run() # アプリを実行

表示


ポイント

  • 他ライブラリと明らかに違う見た目
  • モバイルアプリのようなUI
  • ポップアップがウィンドウ内に出る

まとめ

ライブラリ 学習コスト 見た目 日本語対応 得意分野 向いている用途
Tkinter 低い △(やや古い) シンプルなGUI 小規模ツール / 学習用 / 社内ユーティリティ
PySide 高め ◎(洗練されている) 高機能GUI 業務アプリ / 製品レベル / 長期運用
wxPython ○(ネイティブ) OS密着UI Windows業務ツール / ネイティブ感重視
Kivy 高い ○(モダン) △(TTF指定必須) タッチUI タブレット / 実験的アプリ / クロスプラットフォーム

PythonのGUIライブラリは、それぞれ思想や得意分野が大きく異なります。

  • Tkinter はとにかく手軽で、簡単な業務ツールや学習用途に向いています
  • PySide は見た目・機能ともに完成度が高く、業務アプリや製品レベルの開発に適しています
  • wxPython はOSネイティブなUIを活かせるため、特にWindows向けの業務ツールと相性が良いです
  • Kivy はタッチ操作やモダンなUIを得意とし、タブレットや実験的なアプリ開発に向いています

GUIアプリは最終的に PyInstaller などで実行ファイル(.exe)化することが多いです。
Tkinter は、ファイルサイズが圧倒的に小さいので配布しやすく、PySideKivy は、ライブラリが巨大なため、exe化した際のファイルサイズが大きくなります。

実際に触ってみると、「実装のしやすさ」「日本語表示の扱いやすさ」「環境によるクセ」など、ドキュメントだけでは分からない違いも多く感じました。
今回の比較が、PythonでGUIアプリを作成する際のライブラリ選定の参考になれば幸いです。

91works Tech Blog

Discussion