🍍

FreeSimpleGUIの使い方・クイックスタートガイド

に公開

最近、AI開発(特にRAG)でローカル用のGUIアプリを作る機会がありました。
その際、PySimpleGUIとFreeSimpleGUIを比較したので、共有します。

このサンプルコードをベースにすると、簡単な入力フォームや確認ダイアログを作れます。
PythonスクリプトをサクッとGUI化したいときに便利です。

もしご参考になれば、うれしく思います!

PySimpleGUIではなくFreeSimpleGUIがいい理由

  • PySimpleGUIは、バージョン5から有償化
    • 個人利用は無料
  • Tkinterより楽
  • FreeSimpleGUIは商用でも無償
  • FreeSimpleGUIへの移行は、ライブラリのインストールと、コードのimport文の修正のみ

インストール&インポート

  • インストール
pip install freesimplegui
  • インポート
import FreeSimpleGUI as sg

最小構成のサンプルコード例

以下は、入力フォーム+ボタンの簡単なサンプルです。よく使うパーツを詰め込んでみました。

import FreeSimpleGUI as sg # FreeSimpleGUIライブラリをインポート

sg.theme('DarkAmber') # デザインテーマを設定

# ウィジェットをリストのリストで配置
layout = [
    [sg.Text('送信された値をポップアップ表示します。', size=(30, 1), key='-TEXT-')], # テキストを表示(30文字, 1行)
    [sg.Input('デフォルトテキスト', key='-INPUT-')], # テキスト入力欄 keyでウィジェットに名前を付与
    [sg.Button('送信', key='-SUBMIT-'), sg.Button('終了', key='-EXIT-')] # アクションをトリガーするボタンを並列に配置
]

window = sg.Window('サンプル', layout) # ウィンドウを作成

while True:
    event, values = window.read() # イベント源の文字列と各ウィジェットの辞書

    if event == sg.WIN_CLOSED or event == '-EXIT-': # ×ボタン or 終了ボタン押下で無限ループを抜ける
        break

    if event == '-SUBMIT-': # 送信ボタン押下でポップアップ表示
        sg.popup(values['-INPUT-'])
        window['-TEXT-'].update("ポップアップを表示しました。") # テキスト更新
        window['-SUBMIT-'].update("完了", disabled=True) # ボタンを「送信」→「完了」に変え、無効化
        window['-INPUT-'].update(disabled=True)  # インプットを無効化

window.close() # ウィンドウを閉じる

サンプルコード解説

  1. sg.theme('SystemDefault')
  2. layoutの定義(2次元リスト):layout = [[]]
    1. 各リストはウィジェット
    2. 各ウィジェットには識別子key)をstringで指定する
  3. windowの作成:window = sg.window('タイトル', layout)
  4. 無限ループ
    1. 始点:while True:
    2. if event == sg.WIN_CLOSED or event=='-EXIT-':
      1. break
    3. event, values = window.read()
      1. event(string):無限ループの中で今発生したイベントの識別子を一つだけもつ
      2. values(辞書): すべてのウィジェットの現在の識別子で管理
    4. if event == 識別子 :
      1. イベント発生時の処理:例)window['識別子'].updata()(ウィジェットの更新)など
  5. window.close()

サンプルコードでは触れませんでしたが、[sg.Multiline(size=(80, 30), key='-SHOW_RESULT-')]なんかも便利です。テーマはDarkAmber以外にも、SystemDefaultHotDogStandなど何種類かあります。

補足

個人的に練習で書いたWikiPedia APIをGUIから叩くサンプルコードも、念のため掲載しておきますね。ご参考までに...。

import FreeSimpleGUI as sg
import wikipediaapi

def fetch_wiki_data(term: str) -> dict | None:
    """
    指定された用語(キーワード)の情報をWikipediaから取得する関数
    成功した場合は情報の辞書(wiki_page_data)を返す。失敗した場合はNoneを返す
    :param term: 調査したい用語
    :return wiki_page_data: Wikipediaから取得した情報の辞書
    """

    print(f"Wiikipediaに接続中...")
    wiki_wiki = wikipediaapi.Wikipedia(
        language = "ja",
        user_agent = "search_wiki(Contact: t.facilita@gmail.com)"
    )

    # 指定された用語のページオブジェクトを取得
    wiki_page = wiki_wiki.page(term)

    # 用語がWikipediaに存在しなければNoneを返す
    if not wiki_page.exists():
        print(f"Wikipediaに{term}は存在せず。")
        return None

    print(f"{term}の情報を集めています...。")

    # 取得した情報を辞書にまとめる
    wiki_page_data = {
        "title": wiki_page.title,
        "url": wiki_page.fullurl,
        "summary": wiki_page.summary,
        "full_text": wiki_page.text
    }

    return wiki_page_data

# テーマをセットする
sg.theme("DarkAmber")

# リスト in リストでレイアウトを定義する(keyはウィジェット名)
layout = [
    [sg.Text('FreeSimpleGUI入門', size=(30, 1), font=('Helvetica', 25))],
    [sg.Text('検索語:'), sg.InputText(key='-INPUT_KEYWORD-', size=(40,1))],
    [sg.Button('1. 用語を検索', key='-SEARCH_WIKI-')],
    # 取得したデータを表示するための専用ディスプレイ
    [sg.Multiline(size=(80, 20), key='-OUTPUT-', disabled=True)],
    [sg.Button('サマリー表示', key='-SHOW_SUMMARY-', disabled=True), sg.Button('全文表示', key='-SHOW_FULLTEXT-', disabled=True)],
    [sg.Button('終了', key='-EXIT_BUTTON-')]
]

# Windowの作成
window = sg.Window('Wiki検索', layout)

# --- イベントループ ---

wiki_data = None # 取得したデータを保存しておくための変数

while True:
    event, values = window.read()

    if event == sg.WIN_CLOSED or event == '-EXIT_BUTTON-':
        break

    # --- ステップ1:API呼び出し---
    if event == '-SEARCH_WIKI-':
        term = values['-INPUT_KEYWORD-']
        if not term:
            sg.popup_error('検索語が入力されてないわよ!')
            continue

        # フィードバック
        window['-OUTPUT-'].update("Wikipediaに接続中... ターゲットを捜索...")
        window.refresh()

        # API呼び出し
        wiki_data = fetch_wiki_data(term)

        if wiki_data:
            # 成功したら
            window['-OUTPUT-'].update(f"【{wiki_data['title']}】の情報を取得しました。\n\n" + wiki_data['summary'])
            window['-SHOW_SUMMARY-'].update(disabled=False)
            window['-SHOW_FULLTEXT-'].update(disabled=False)
        else:
            # 失敗したら
            sg.popup_error(f"「{term}」は見つからなかったわ。")
            wiki_data = None # データ変数をクリア
            window['-SHOW_SUMMARY-'].update(disabled=True)
            window['-SHOW_FULLTEXT-'].update(disabled=True)

    # --- ステップ2:表示切替 ---
    # SEARCH_WIKIが成功して、wiki_dataにデータがある時だけ、これらのボタンは意味を持つ
    if event == '-SHOW_SUMMARY-':
        if wiki_data:
            window['-OUTPUT-'].update(wiki_data['summary'])

    if event == '-SHOW_FULLTEXT-':
        if wiki_data:
            window['-OUTPUT-'].update(wiki_data['full_text'])

window.close()

Discussion