Python wxPython: wx.AcceleratorTableでショートカットキーを簡単設定!使い方を徹底解説

Python

PythonのGUIライブラリ wxPython を使ってデスクトップアプリを開発していると、「Ctrl+Sで保存したい」「Ctrl+Qで終了したい」といった、キーボードショートカット(アクセラレータキー)を実装したくなる場面が必ず訪れます。

この記事では、wxPythonでショートカットキーを実装するための専用機能である wx.AcceleratorTable に焦点を当て、その基本的な使い方からメニューと連動させる実践的なサンプルコードまで、初心者にも分かりやすく徹底的に解説します。

この記事を読み終える頃には、あなたのwxPythonアプリに自由自在にショートカットキーを設定できるようになっているはずです。

はじめに: wxPythonアプリの操作性を格段に上げる方法

wxPythonアプリの「使いやすさ」を向上させる上で、ショートカットキーの存在は非常に重要です。

「アプリに Ctrl+S のようなショートカットキーを付けたい…でもどうやればいいんだろう?」 「メニューをクリックする操作とは別に、キーボードからも実行できるようにしたい」

このような悩みを抱えている方に、wx.AcceleratorTable は明確な解決策を提供します。

この記事で解説する wx.AcceleratorTable を使えば、キー操作とプログラムの処理を結びつけることが可能になり、アプリの操作性をプロフェッショナルなレベルに引き上げることができます。

wx.AcceleratorTable とは?

wx.AcceleratorTable とは、ひと言でいうと**「ショートカットキーの対応表」**です。

これは、「どのキー操作が(例: Ctrl + S)」、「どの処理(イベントID)に結びつくか」を定義したリスト(テーブル)そのものを指します。

wx.AcceleratorTable は、それ単体で存在するのではなく、個々のショートカットキー設定である wx.AcceleratorEntry の集まり(リスト)として機能します。

  • wx.AcceleratorEntry: 「Ctrl+S を押したら、ID: 5001番の処理を実行せよ」という1行の定義
  • wx.AcceleratorTable: wx.AcceleratorEntry の定義を複数まとめた対応表(本)

この「対応表(Table)」を作成し、アプリのメインウィンドウ(wx.Frame)にセットすることで、ショートカットキーが有効になります。

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

wx.AcceleratorTable の実装は、以下の3つの簡単なステップで完了します。非常にシンプルなので、この流れをまず掴みましょう。

  1. ステップ1: ショートカットキーを定義する (wx.AcceleratorEntry)
  2. ステップ2: 対応表を作成する (wx.AcceleratorTable)
  3. ステップ3: フレーム(ウィンドウ)に設定する (SetAcceleratorTable)

ステップ1: ショートカットキーを定義する (wx.AcceleratorEntry)

まず、個々のショートカットキー設定(Entry)を作成します。

wx.AcceleratorEntry は、「修飾キー」「キーコード」「イベントID」の3つを主に指定して作成します。

# 例: Ctrl + S を押したら、IDが 1001 のイベントを実行する
entry = wx.AcceleratorEntry(
    flags=wx.ACCEL_CTRL,  # 修飾キー (Ctrl)
    keyCode=ord('S'),     # キーコード (Sキー)
    cmd=1001              # イベントID (任意の整数)
)

主な引数の解説

  • flags (修飾キー): どの修飾キー(CtrlAltShift)と組み合わせるかを指定します。
    • wx.ACCEL_CTRL: Ctrl キー
    • wx.ACCEL_ALT: Alt キー
    • wx.ACCEL_SHIFT: Shift キー
    • wx.ACCEL_NORMAL: 修飾キーなし (例: Deleteキー単体)
    • 複数組み合わせる場合は | (パイプ) を使います (例: wx.ACCEL_CTRL | wx.ACCEL_SHIFT)
  • keyCode (キーコード): どのキーを押すかを指定します。
    • アルファベット: ord('S'), ord('Q') のように ord() を使って指定します(大文字推奨)。
    • 特殊キー: wx.WXK_DELETE (Deleteキー), wx.WXK_F1 (F1キー), wx.WXK_RETURN (Enterキー) など、wx.WXK_ プレフィックスで定義されています。
  • cmd (イベントID): このショートカットが押されたときに、どの処理を呼び出すかを識別するための「番号」です。 これは、メニューアイテムのIDや、後で Bind するイベントのIDと一致させる必要があります。wx.ID_ANYwx.NewIdRef() を使って自動生成することも、1001 のように固定の整数を自分で決めることも可能です。

ステップ2: 対応表を作成する (wx.AcceleratorTable)

次に、ステップ1で作成した wx.AcceleratorEntry のリスト(Pythonのタプルやリスト)を wx.AcceleratorTable のコンストラクタに渡して、「対応表」オブジェクトを作成します。

# ステップ1で作成したEntry定義をリスト(またはタプル)にまとめる
entries = [
    # Ctrl + S (ID: 1001)
    wx.AcceleratorEntry(wx.ACCEL_CTRL, ord('S'), 1001),
    # Alt + F4 (ID: 1002)
    wx.AcceleratorEntry(wx.ACCEL_ALT, wx.WXK_F4, 1002)
]

# リストを渡して AcceleratorTable を作成
accel_table = wx.AcceleratorTable(entries)

ステップ3: フレーム(ウィンドウ)に設定する

最後に、作成した wx.AcceleratorTable オブジェクトを、メインウィンドウ(wx.Frame を継承したクラスなど)の SetAcceleratorTable() メソッドで登録します。

# self は wx.Frame を想定
self.SetAcceleratorTable(accel_table)

これだけで、ウィンドウがアクティブな時に Ctrl+SAlt+F4 が押されると、それぞれID 1001, 1002 に関連付けられたイベントが発生するようになります。

あとは、これらのIDに対応するイベントハンドラ(処理関数)を Bind すれば、ショートカットキーが機能します。

実践!メニューと連動するショートカットキーの実装

wx.AcceleratorTable の最も一般的な使い方は、メニューバーの項目とショートカットキーを連動させることです。

例えば、「ファイル」メニューの「保存」をクリックする操作と、Ctrl+S を押す操作を、同じ処理(保存処理)に結びつける方法を見ていきましょう。

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

以下は、wx.Frame を作成し、メニューバーと wx.AcceleratorTable を設定する、すぐに動作するサンプルコードです。

「保存 (Ctrl+S)」と「終了 (Alt+F4)」の2つのショートカットキーを実装しています。

import wx

# メニューやショートカットキーで使用するIDを定義
# wx.NewIdRef() を使うのが現代的ですが、分かりやすさのため固定IDを使います
ID_SAVE = 1001
ID_EXIT = 1002

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        super(MyFrame, self).__init__(parent, title=title, size=(400, 300))

        # 1. メニューバーの作成
        self.CreateMenuBar()

        # 2. AcceleratorTable の作成と設定
        self.SetupAcceleratorTable()

        # 3. イベントハンドラをBind
        self.Bind(wx.EVT_MENU, self.OnSave, id=ID_SAVE)
        self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)

        # ステータスバー(ログ表示用)
        self.CreateStatusBar()
        self.SetStatusText("wxPython AcceleratorTable サンプル")

        self.Show(True)

    def CreateMenuBar(self):
        """メニューバーを作成する"""
        menu_bar = wx.MenuBar()
        
        # [ファイル] メニュー
        file_menu = wx.Menu()
        
        # 「保存」メニューアイテム
        # メニューテキストに "\tCtrl+S" を追加すると、見た目にもショートカットが表示される
        save_item = wx.MenuItem(file_menu, ID_SAVE, "保存(&S)\tCtrl+S")
        file_menu.Append(save_item)
        
        file_menu.AppendSeparator()
        
        # 「終了」メニューアイテム
        exit_item = wx.MenuItem(file_menu, ID_EXIT, "終了(&X)\tAlt+F4")
        file_menu.Append(exit_item)
        
        menu_bar.Append(file_menu, "ファイル(&F)")
        
        # フレームにメニューバーを設定
        self.SetMenuBar(menu_bar)

    def SetupAcceleratorTable(self):
        """AcceleratorTableを設定する"""
        
        # --- ここが重要 ---
        # ステップ1 & 2: Entry のリストを作成
        entries = [
            # Ctrl + S を ID_SAVE (1001) に割り当て
            wx.AcceleratorEntry(wx.ACCEL_CTRL, ord('S'), ID_SAVE),
            
            # Alt + F4 を ID_EXIT (1002) に割り当て
            wx.AcceleratorEntry(wx.ACCEL_ALT, wx.WXK_F4, ID_EXIT)
        ]
        
        # AcceleratorTable オブジェクトを作成
        accel_table = wx.AcceleratorTable(entries)
        
        # ステップ3: フレームに設定
        self.SetAcceleratorTable(accel_table)
        # --- ここまで ---

    # --- イベントハンドラ(実際の処理) ---
    
    def OnSave(self, event):
        """保存処理(メニューまたはCtrl+Sで呼ばれる)"""
        self.SetStatusText("保存処理が実行されました (Ctrl+S)")
        print("Saving document...")

    def OnExit(self, event):
        """終了処理(メニューまたはAlt+F4で呼ばれる)"""
        self.SetStatusText("終了処理が実行されました (Alt+F4)")
        self.Close(True)


# アプリケーションの実行
if __name__ == '__main__':
    app = wx.App()
    frame = MyFrame(None, "AcceleratorTable Demo")
    app.MainLoop()

コードのポイント解説

このサンプルコードの最大のポイントは、IDの一致です。

  1. メニューアイテムのID: save_item = wx.MenuItem(..., ID_SAVE, ...) ここで、「保存」メニューアイテムに ID_SAVE (1001) を割り当てています。
  2. AcceleratorEntryのID: wx.AcceleratorEntry(wx.ACCEL_CTRL, ord('S'), ID_SAVE) ここで、Ctrl+S の操作に ID_SAVE (1001) を割り当てています。
  3. イベントハンドラのBind: self.Bind(wx.EVT_MENU, self.OnSave, id=ID_SAVE) ここで、ID_SAVE (1001) に紐づく wx.EVT_MENU(メニューイベント)が発生したら、self.OnSave 関数を呼び出すように設定しています。

wx.AcceleratorTable によって Ctrl+S が押されると、内部的に ID_SAVEwx.EVT_MENU イベントが発生します。これは、ユーザーが「保存」メニューをクリックした時と全く同じイベントです。

そのため、Bind 設定が一つあれば、メニューからの操作とショートカットキーからの操作の両方に対応できるのです。

また、メニューテキストに \tCtrl+S のように \t(タブ)とショートカット名を追加しておくと、WindowsやLinux (GTK) など多くの環境で、メニューの右側にショートカットキーが自動的に表示され、ユーザーに親切です。

よくある質問と注意点

最後に、wx.AcceleratorTable を使う際につまずきやすいポイントをQ&A形式で解説します。

Q1. メニュー項目がない処理にもショートカットを割り当てられる?

A: はい、可能です。

wx.AcceleratorTable は、必ずしもメニューアイテムと連動させる必要はありません。

例えば、「Deleteキーが押されたら、選択中のアイテムを削除する」という処理を実装したい場合、メニューに「削除」がなくても問題ありません。

  1. wx.NewIdRef() や任意の整数で、その処理専用のIDを決めます(例: ID_DELETE = 2001)。
  2. wx.AcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_DELETE, ID_DELETE) のようにEntryを作成し、Tableに登録します。
  3. self.Bind(wx.EVT_MENU, self.OnDeleteHandler, id=ID_DELETE) のように、wx.EVT_MENU としてBindします。(ショートカットキーイベントは wx.EVT_MENU として処理されるためです)

これで、Delete キーが押されると OnDeleteHandler が直接呼び出されます。

Q2. ショートカットキーが効かない・反応しない時のチェックリスト

ショートカットキーが反応しない場合、以下の点を確認してみてください。

  • SetAcceleratorTable() を呼び忘れていないか? wx.AcceleratorTable オブジェクトを作成しただけではダメで、必ず wx.FrameSetAcceleratorTable() メソッドで登録する必要があります。
  • イベントIDは一致しているか? wx.AcceleratorEntrycmd(ID)と、self.Bind(wx.EVT_MENU, ...)id が一致しているか確認してください。
  • イベントハンドラのBindを忘れていないか? wx.AcceleratorTable はイベントを発生させるだけです。そのイベントを受け取る Bind 処理がなければ、何も起こりません。
  • キーコードやフラグは正しいか? アルファベットは ord('S') のように指定していますか? wx.ACCEL_CTRL などのフラグは正しく設定されていますか?
  • ウィンドウ(フレーム)がアクティブか? ショートカットキーは、それが設定されたフレームがアクティブ(フォーカスを持っている)状態でないと反応しません。

まとめ

この記事では、wxPythonでショートカットキーを実装するための wx.AcceleratorTable の使い方を、基本的な3ステップから実践的なメニュー連動のサンプルコードまで詳しく解説しました。

  • wx.AcceleratorTable は「ショートカットキーの対応表」です。
  • wx.AcceleratorEntry で個々のキー設定を定義します。
  • wx.AcceleratorTable オブジェクトを作成し、SetAcceleratorTable() でフレームに登録します。
  • メニューアイテムのIDと AcceleratorEntry のIDを一致させることで、簡単にメニューとショートカットを連動させることができます。

wx.AcceleratorTable をマスターすれば、wxPythonアプリのUX(ユーザー体験)が格段に向上します。ぜひあなたのアプリにも、便利なショートカットキーを実装してみてください。

コメント

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