Python wxPython: wx.ConfigBaseでアプリ設定を保存・復元する基本

Python

PythonのGUIライブラリ wxPython でアプリケーションを開発していると、多くの人が直面する課題があります。

「アプリを起動するたびに、ウィンドウがいつも同じ初期位置に表示されてしまう…」 「ユーザーが入力した設定(例えば、APIキーやユーザー名)を、次回起動時にも引き継ぎたい」

これらの悩みは、アプリケーションの「使いやすさ(UX)」に直結します。ユーザーが快適に使えるアプリを作るためには、設定をPCに保存し、次回起動時に復元する「永続化」の仕組みが不可欠です。

この記事では、wxPythonが標準で提供している設定管理機能 wx.ConfigBase(と、その具体的な実装である wx.Config)に焦点を当て、アプリの設定を簡単に保存・復元する方法を、初心者にも分かりやすく解説します。

はじめに: アプリを閉じても設定が消えないようにするには?

アプリを終了すると、メモリ上にあった情報はすべて消えてしまいます。wx.Frame のウィンドウサイズや位置、wx.TextCtrl に入力された内容も例外ではありません。

この問題を解決するのが wx.ConfigBase の役割です。

この記事を読み終える頃には、wx.Config を使って以下のことができるようになります。

  • アプリのウィンドウサイズと位置を記憶させる
  • ユーザーが入力した設定値をPCに保存する
  • 次回起動時に、保存した設定を安全に読み込む

対象読者は、wxPythonでのアプリ開発経験が少しあり、アプリのUXをもう一段階レベルアップさせたいと考えている初心者〜中級者の方です。

wx.ConfigBase とは?

wx.ConfigBase とは、ひと言でいうと**「アプリ設定を保存・復元するための設計図(基底クラス)」**です。

これはあくまで「こういう機能(Read, Writeなど)を持つべき」というルールを定めた抽象的なクラスであり、通常、私たちがプログラムで直接この wx.ConfigBase を使うことはありません

私たちが実際に使うのは、wx.ConfigBase のルールを具体的に実装した、以下のどちらかのクラスです。

  1. wx.Config (推奨) OS標準の方法で設定を保存します。これが最も一般的で、OSに馴染む方法です。
    • Windows: レジストリ (HKEY_CURRENT_USER\Software\...)
    • macOS: plist ファイル (~/Library/Preferences/...)
    • Linux: INI形式のテキストファイル (~/.config/...)
  2. wx.FileConfig OSに関わらず、指定したINIファイルに設定を保存します。

wx.Config を使う最大のメリットは、開発者が OS間の違い(レジストリか、INIファイルか)を一切意識しなくてよいことです。wx.Config がOSを自動で判別し、最適な場所へ保存・復元を行ってくれます。

この記事では、最も一般的で推奨される wx.Config の使い方を解説します。

wx.Config の基本的な使い方 3ステップ

wx.Config を使った設定の保存・復元は、たった3つのステップで完了します。

  1. ステップ1: wx.Config オブジェクトを作成する
  2. ステップ2: 設定を書き込む (Write)
  3. ステップ3: 設定を読み込む (Read)

ステップ1: wx.Config オブジェクトを作成する

まず、設定を管理するための wx.Config インスタンスを作成します。このとき、「アプリ名」と「開発者(会社)名」を指定するのが一般的です。

import wx

# Configオブジェクトを作成
# これにより、保存場所が決定されます (例: レジストリの Software\MyCompany\MyApp)
config = wx.Config(
    appName="MyApp",         # アプリケーション名
    vendorName="MyCompany"   # 開発者名・会社名
)

appNamevendorName は、設定がどこに保存されるかを決める重要なキーとなります。OSは、この2つの名前を使って設定をグループ化します(例: Windowsレジストリの HKEY_CURRENT_USER\Software\MyCompany\MyApp)。

TIPS: 実際には、wx.AppOnInitself.SetAppName("MyApp")self.SetVendorName("MyCompany") を設定し、アプリ全体で config = wx.Config.Get() を呼び出して唯一の(シングルトン)設定オブジェクトにアクセスする方法がより一般的です。

ステップ2: 設定を書き込む (Write)

設定を保存するには Write(key, value) メソッドを使います。

key (キー) には、設定の名前を文字列で指定します。このキーは / (スラッシュ) を使って、フォルダのパスのように階層構造で管理するのがベストプラクティスです。

# 文字列を書き込む
config.Write("/Settings/Username", "Taro Yamada")

# 整数を書き込む
config.WriteInt("/Window/Width", 800)

# 真偽値を書き込む
config.WriteBool("/Options/CheckForUpdates", True)

# (重要) 変更を即座にファイル/レジストリに反映させる
config.Flush()

Write は型ごとにメソッドが分かれています (WriteString, WriteInt, WriteBool など)。WriteWriteString のエイリアス(別名)です。 最後に Flush() を呼ぶと、メモリ上の変更が即座にディスク(またはレジストリ)に書き込まれることが保証されます。

ステップ3: 設定を読み込む (Read)

設定を読み込むには Read(key, defaultValue) メソッドを使います。

ここで最も重要なのが、defaultValue (デフォルト値) を指定することです。

# 文字列を読み込む (もしキーが存在しなければ "Guest" が返る)
username = config.Read("/Settings/Username", defaultValue="Guest")

# 整数を読み込む (もしキーが存在しなければ 640 が返る)
width = config.ReadInt("/Window/Width", defaultValue=640)

# 真偽値を読み込む (もしキーが存在しなければ False が返る)
check_updates = config.ReadBool("/Options/CheckForUpdates", defaultValue=False)

なぜデフォルト値が重要かというと、アプリを初めて起動した時は、まだ設定が何も保存されていないからです。その際に Read を試みると、キーが存在せずエラーになるか、予期せぬ値が返ってきてしまいます。

defaultValue を指定しておけば、「キーが存在しなかった場合は、この値を使ってね」という意味になり、初回起動時でも安全にプログラムを実行できます。

実践!ウィンドウのサイズと位置を保存・復元する

wx.Config の最も代表的なユースケースである、「ウィンドウのサイズと位置の保存・復元」を実装してみましょう。

  • 復元(読み込み): ウィンドウが作成される時 (__init__)
  • 保存(書き込み): ウィンドウが閉じられる直前 (wx.EVT_CLOSE)

この2つのタイミングで処理を行うのが基本です。

サンプルコード全体 (コピペOK)

以下のコードは、起動・終了するたびにウィンドウのサイズと位置を記憶します。

import wx

# アプリ名と開発者名を定義
APP_NAME = "MyConfigApp"
VENDOR_NAME = "MyDev"

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        # --- (A) まずデフォルト値でウィンドウを作成 ---
        # NOTE: ここではまだReadせず、デフォルト値で初期化するのが安全
        super(MyFrame, self).__init__(parent, title=title, 
                                      pos=(100, 100), size=(400, 300))

        # --- (B) Configオブジェクトの準備 ---
        # アプリ全体で共通のConfigインスタンスを取得
        self.config = wx.Config(appName=APP_NAME, vendorName=VENDOR_NAME)

        # --- (C) 設定の読み込みと適用 ---
        self.LoadSettings()

        # --- (D) 終了イベントのバインド ---
        # ウィンドウが閉じられる直前に OnClose を呼び出す
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        self.Show(True)

    def LoadSettings(self):
        """設定を読み込んでウィンドウに適用する"""
        self.SetStatusText("設定を読み込みました。")
        
        # デフォルト値を設定しつつ、保存された値を読み込む
        # 初回起動時はデフォルト値が使われる
        pos_x = self.config.ReadInt("/Window/X", 100)
        pos_y = self.config.ReadInt("/Window/Y", 100)
        size_w = self.config.ReadInt("/Window/Width", 400)
        size_h = self.config.ReadInt("/Window/Height", 300)
        
        # 読み込んだ設定をウィンドウに適用
        self.SetPosition((pos_x, pos_y))
        self.SetSize((size_w, size_h))

    def SaveSettings(self):
        """現在のウィンドウ設定を保存する"""
        self.SetStatusText("設定を保存しました。")

        # 現在のウィンドウ位置とサイズを取得
        pos = self.GetPosition()
        size = self.GetSize()
        
        # Configオブジェクトに書き込む
        self.config.WriteInt("/Window/X", pos.x)
        self.config.WriteInt("/Window/Y", pos.y)
        self.config.WriteInt("/Window/Width", size.width)
        self.config.WriteInt("/Window/Height", size.height)
        
        # 変更をディスクに即時反映
        self.config.Flush()

    def OnClose(self, event):
        """ウィンドウ終了時に呼び出される"""
        
        # (重要) まず設定を保存する
        self.SaveSettings()
        
        # (重要) event.Skip() を呼び、wxPythonに「この後は通常の終了処理を続けて良い」と伝える
        event.Skip()

# アプリケーションの実行
if __name__ == '__main__':
    # (推奨) Appオブジェクトにもアプリ名を設定
    app = wx.App()
    app.SetAppName(APP_NAME)
    app.SetVendorName(VENDOR_NAME)
    
    frame = MyFrame(None, "wx.ConfigBase デモ")
    app.MainLoop()

コードのポイント解説

このコードには2つの重要なポイントがあります。

  1. wx.EVT_CLOSE イベントのバインド: self.Bind(wx.EVT_CLOSE, self.OnClose) は、「ユーザーがXボタンを押すなどしてウィンドウを閉じようとしたら、self.OnClose 関数を呼び出してください」という命令です。
  2. OnClose 内の event.Skip(): OnClose 関数内で SaveSettings() を呼び出した後、event.Skip() を実行しています。これは非常に重要です。もし Skip() を呼ばないと、wxPythonは「開発者が独自の終了処理を行った」と判断し、ウィンドウを閉じる処理を中断してしまいますevent.Skip() は、「こちらの処理(保存)は終わったので、あとはよろしく(通常の終了処理を続けてください)」とwxPythonに伝える役割を果たします。

よくある質問とTIPS

最後に、wx.ConfigBase に関するよくある疑問点をまとめます。

Q1. 設定ファイルは具体的にどこに保存される?

A: wx.Config を使った場合、OSによって異なります。

  • Windows: レジストリの HKEY_CURRENT_USER\Software\VendorName\AppName (上記サンプルの場合 Software\MyDev\MyConfigApp)
  • macOS: ~/Library/Preferences/AppName.plist (例: MyConfigApp.plist)
  • Linux: ~/.config/AppName/AppName.conf (INIファイル形式)

もし、OS標準の場所ではなく、アプリの実行ファイルと同じフォルダに config.ini のようなファイル名で保存したい(ポータブルアプリ化したい)場合は、wx.Config の代わりに wx.FileConfig を使います。

# アプリと同じフォルダに "config.ini" という名前で保存する場合
import os
app_path = os.path.dirname(os.path.abspath(__file__))
config_path = os.path.join(app_path, "config.ini")

config = wx.FileConfig(
    appName=APP_NAME,
    vendorName=VENDOR_NAME,
    localFilename=config_path,
    style=wx.CONFIG_USE_LOCAL_FILE
)

Q2. wx.ConfigBase と wx.Config の違いは?

A: 改めて整理します。

  • wx.ConfigBase (基底クラス): 設定機能の「インターフェース(設計図)」です。「ReadWrite ができるべき」と決めているだけで、どうやって保存するかは知りません。
  • wx.Config (具象クラス): wx.ConfigBase の設計図に基づき、OS標準の方法(レジストリ等)で保存・復元を実装したクラスです。
  • wx.FileConfig (具象クラス): wx.ConfigBase の設計図に基づき、INIファイルで保存・復元を実装したクラスです。

基本的には、OSに準拠した wx.Config を選んでおけば、ユーザーにとっても違和感のない(管理しやすい)アプリケーションになります。

まとめ

この記事では、wxPythonでアプリケーションの設定を永続化するための wx.ConfigBase の仕組みと、その具体的な実装である wx.Config の使い方を解説しました。

  • wx.Config を使うと、OSの違い(レジストリやINIファイル)を意識せずに設定を保存できます。
  • appNamevendorName で設定の保存場所が決まります。
  • Write (WriteInt 等) で設定を書き込みます。
  • Read (ReadInt 等) で設定を読み込みます。この時、初回起動に備えて defaultValue を必ず指定します
  • wx.EVT_CLOSE イベントを捕捉し、ウィンドウが閉じる直前に設定を Write するのが定石です。

wx.Config をマスターして、ユーザーが「使いやすい」と感じる、気の利いたアプリケーションを目指しましょう。

コメント

タイトルとURLをコピーしました