ホーム < ゲームつくろー! < IKD備忘録

wxWidgets
エディットボックスを表示させてみる

(2010. 5. 4)


 コントロールの中で積極的な入力支援をしてくれる物と言えばエディットボックスです。アプリでもWebでも世の中エディットボックス祭りです(笑)。wxWidgetsでは簡単にエディットボックスを出す事ができます。



@ エディットボックスクラス

エディットボックスはwxTextCtrlクラスが担います。まずはこのクラスのオブジェクトをフレーム内で作成します:

#include "wx/textctrl.h"

TestFrame::TestFrame(const wxString &title, const wxSize &size) :
    wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, size)
{
    textCtrl = new wxTextCtrl(panel, TextCtrlID, "TextCtrl", wxPoint(20, 140));
}

はい、これだけでもうエディットボックス(テキストコントロール)がお目見えします(^-^)、

左下のです。コンストラクタで渡した初期文字列が表示されています。

 エディットボックスで必要なのは入力した情報を取り出す仕組みです。例えばエディットボックスに入力した情報をリストに追加する場合は、入力確定を捉えて文字列をリストに渡す必要があります。



A 入力確定を捉える

 エディットボックスの入力確定には「Enterキーを押す」と「フォーカスを外す」があります。このうちフォーカスアウトはちょっとまだ調べがついていませんが、Enter確定は最初から用意されています。

 Enter確定時にエディットボックスはwxEVT_COMMAND_TEXT_ENTERイベントを発行します。これをハンドラで捉えればOKです。ただし、このイベント発行を有効にするには、コンストラクタでwxTE_PROCESS_ENTERフラグを付記する必要があります:

#include "wx/textctrl.h"

TestFrame::TestFrame(const wxString &title, const wxSize &size) :
    wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, size)
{
    textCtrl = new wxTextCtrl(
        panel, TextCtrlID, "TextCtrl", wxPoint(20, 140), wxDefaultSize, wxTE_PROCESS_ENTER);
    Connect(TextCtrlID, wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(TestFrame::OnTextEnter));
}



B 文字列を設定・取得する

 入力した文字列を得るにはwxTextCtrl::GetValメソッドを用います。逆にテキストを設定するにはSetValueメソッドを用います。直感的でわかりやすいインターフェイスですね。例えばtextCtrlオブジェクトに入力されている文字列をtextCtrl2オブジェクトにコピーするには次のようにします:

// テキストコントロール2へコピー
textCtrl2->SetValue( textCtrl->GetValue() );

 テキストコントロールには他にも色々なメソッドが提供されていますが、とりあえず表示出来て文字列の設定・取得ができればこのコントロールは使えたも同然です。



<追記 2010. 6. 3>
C フォーカスアウトを捉える

 Aで「フォーカスアウトが調べがつかない」と書きましたが、その後大変有力な情報をWLK様より頂きました。ありがとうございます!!

 フォーカスアウトはデフォルトでは捉えられないのですが、エディットボックスの派生クラスを作ると解決できる事がわかりました。以下にその方法を記述します。

 wxWidgetsのウィンドウ自体はフォーカスが無くなった時にEVT_KILL_FOCUSというメッセージを受け取る事ができます。エディットボックス(wxTextCtrl)もウィンドウなのでこのメッセージを受け取れます。このメッセージを受けた時に自分の親ウィンドウに対して「フォーカスが切れたよ〜」と教えてあげればいいんです。

 まずはwxTextCtrlの派生クラスであるKillFocusedTextCtrlクラスを次のように宣言します:

KillFocusedTextCtrl.h
#ifndef KillFocusedTextCtrl_h
#define KillFocusedTextCtrl_h

#include "wx/textctrl.h"

class KillFocusedTextCtrl : public wxTextCtrl {
public:
    KillFocusedTextCtrl(wxWindow *parent, wxWindowID id,
        const wxString& value = wxEmptyString,
        const wxPoint& pos = wxDefaultPosition,
        const wxSize& size = wxDefaultSize,
        long style = 0,
        const wxValidator& validator = wxDefaultValidator,
        const wxString& name = wxTextCtrlNameStr);
    virtual ~KillFocusedTextCtrl() {}

    // フォーカスキル
    void OnKillForcus(wxFocusEvent& event);

    DECLARE_EVENT_TABLE();
};

DECLARE_EVENT_TYPE(EVT_TEXT_CTRL_KILL_FOCUS, -1)

#endif

 コンストラクタはwxTextCtrlのそれと同じにします。フォーカスが切れた時に呼ばれるのがOnKillFocusメソッドです。
DECLARE_EVENT_TYPEマクロは新しいイベントを登録するためのマクロです。このクラスを使う親ウィンドウはこのイベント名を受けて「TextCtrlのフォーカスが切れた!」と知る事になります。

 このクラスの実装は次のとおりです:

KillFocusedTextCtrl.cpp
#include "KillFocusedTextCtrl.h"

DEFINE_EVENT_TYPE(EVT_TEXT_CTRL_KILL_FOCUS)

BEGIN_EVENT_TABLE(KillFocusedTextCtrl, wxTextCtrl)
    EVT_KILL_FOCUS(OnKillForcus)
END_EVENT_TABLE()

KillFocusedTextCtrl::KillFocusedTextCtrl(
    wxWindow *parent,
    wxWindowID id,
    const wxString& value,
    const wxPoint& pos,
    const wxSize& size,
    long style,
    const wxValidator& validator,
    const wxString& name) :
    wxTextCtrl(parent, id, value, pos, size, style, validator, name) {}

    // フォーカスキル
    void KillFocusedTextCtrl::OnKillForcus(wxFocusEvent& event) {
        if( GetParent() ){
            wxCommandEvent newEvent(EVT_TEXT_CTRL_KILL_FOCUS, GetId());
            GetParent()->ProcessEvent(newEvent);
        }
        event.Skip();
    }

 実装では、最初にDEFINE_EVENT_TYPEマクロで宣言部で定義したEVT_TEXT_CTRL_KIL_FOCUSイベントを実際に実装しています。続いてイベントとハンドラを結びつけています。

 フォーカスキルメソッドの中がポイントです。このメソッドはエディットボックスのフォーカスがはずれた時に呼び出されます。まず自分の親がいるかをチェックします。いなければ何もしません。親がいた場合、その親に対してイベントを発行します。そのイベントを作っているのが太文字部分です。wxCommandEventの第1引数はイベント名、第2引数はそのイベントを発行した人のIDとなります。作ったイベントを親のProcessEventメソッドを使って飛ばします。

 このクラスを使う親の方は次のとおりです。Aのソースをちょこっとだけ改良するだけでできてしまいます:

#include "KillFocusedTextCtrl.h"

BEGIN_EVENT_TABLE(TestFrame, wxFrame)
    EVT_COMMAND(TextCtrlID, EVT_TEXT_CTRL_KILL_FOCUS, TestFrame::OnKillForcus)
END_EVENT_TABLE()

TestFrame::TestFrame(const wxString &title, const wxSize &size) :
    wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, size)
{
    textCtrl = new KillFocusedTextCtrl(
        panel, TextCtrlID, "TextCtrl", wxPoint(20, 140), wxDefaultSize, wxTE_PROCESS_ENTER);
    Connect(TextCtrlID, wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(TestFrame::OnTextEnter));
}

// フォーカスキル
void TestFrame::OnKillForcus(wxCommandEvent& event) {
}

 先程作成したヘッダーをインクルードして、Commandイベントとして上の太文字のようにイベントとハンドラを結びつけます。ここでEVT_TEXT_CTRL_KILL_FOCUSが出てくるわけです。コンストラクタの中ではKillFocusedTextCtrlオブジェクトを作ります。これはAとほぼ一緒ですね。後はハンドラであるOnKillFocusメソッドを設けるだけです。これでエディットボックスのフォーカスが切れる度にこのメソッドが呼ばれます。複数のエディットボックスがある場合は都度ハンドラを作るか、同じハンドラを呼ぶようにしてevent内に渡されているIDで識別します。

(参考サイト)
MinGW - wxWidgets - SlideValue (http://www.or2.fiberbit.net/ysfactory/a1/MinGWwxWidgets/MinGW-wxWidgets-SlideValue.html)