.xrcファイルはxml形式なので、独自のタグを入れられる。ただしそれを解析する機能がデフォルトではないので、ハンドラを用意する必要がある。
.xrcファイルにはコントロールwx_my_Buttonという識別子でボタンを配置する。このボタンはC++では標準のボタン(wxButton)として生成する。wxButtonのハンドラを書き換えられないので、wx_my_Buttonのハンドラを作成し、中でwxButtonを作成する。
<?xml version="1.0" ?> <resource version="2.3.0.1"> <!-- トップレベルはコントロールである必要がある。パネルを作成。 --> <object class="wxPanel" name="myContainerPanel"> <bg>#00FF00</bg> <!-- 名前 myButton を追加 --> <object class="wx_my_Button" name="myButton"> <myoption attr="5">ユーザー定義オプション</myoption> <label>ボタン</label> </object> </object> </resource>
// wxXmlNode を使うために必要 #include <wx/xml/xml.h>
SetClientDataで値のインスタンス(ここではmyoption_dataの変数)へのポインタをvoid*で指定する。
struct myoption_data { int attr; wxString str; };
GetParamNodeの使用にはwx/xml/xml.hが必要。
// .xrcから独自タグを読み込むには、自作ウィジェットをwxXmlResourceが読み込むための // ハンドラを作成して登録する必要がある class MyButtonXmlHandler : public wxXmlResourceHandler { public: MyButtonXmlHandler() : wxXmlResourceHandler() { AddWindowStyles(); } virtual wxObject* DoCreateResource() override { XRC_MAKE_INSTANCE(mybutton, wxButton); // 普通のボタンを作成 // プロパティの設定 mybutton->Create( m_parentAsWindow, GetID(), GetText("label"), GetPosition(), GetSize(), GetStyle(), wxDefaultValidator, GetName() );
// タグ名 wxString tagname = "myoption"; // データを格納する構造体のインスタンスを作成 // あとで解放しなければいけない myoption_data *pdata = new myoption_data; // 値を取得 // GetTextでも取得できるが、GetTextは\nや$を勝手にエスケープしたり置換したりするので // 内容をそのまま取得できるGetParamValueを使う wxString myopt = GetParamValue(tagname); if (!myopt.IsEmpty()) { pdata->str = myopt; } // 属性を取得 wxXmlNode* node = GetParamNode(tagname); if (node) { wxString attr = node->GetAttribute("attr"/*属性名*/, "0"/*初期値*/); pdata->attr = wxAtoi(attr); } mybutton->SetClientData(pdata);// データをコントロールに指定
SetupWindow(mybutton); return mybutton; } // このハンドラが、xrc内に定義された"MyControl"というウィジェットを作成できることを示すために必要 virtual bool CanHandle(wxXmlNode* node) override { // 生成するのはただのボタンだが、wxButtonのハンドラを置換はできないので // 別のクラス名を識別子にする。 return IsOfClass(node, "wx_my_Button"); } // wxCreateObject() ,GetClassInfo() ,ms_classInfo,wxCreateObject()が定義される wxDECLARE_DYNAMIC_CLASS(MyButtonXmlHandler); }; // 自作ウィジェットのハンドラを登録 IMPLEMENT_DYNAMIC_CLASS(MyButtonXmlHandler, wxXmlResourceHandler)
生成されるのは普通のwxButtonなので、生成時にAddHandlerしておくこと以外には特別なことはしない。ただしハンドラ内でnewしたmyoption_dataのポインタは自分で削除しなければいけないので、wxEVT_DESTROYに後始末用関数をバインドする。
// ウィンドウ作成 class MyFrame : public wxFrame { public: void PostCreate() { wxXmlResource::Get()->InitAllHandlers();// 初期化 // カスタムコントロールのハンドラを登録 wxXmlResource::Get()->AddHandler(new MyButtonXmlHandler); wxXmlResource::Get()->Load(R"(C:\test\myctrl.xrc)"); // ファイル読み込み wxXmlResource::Get()->LoadPanel(this, "myContainerPanel"); // GUIの生成 this->Layout(); // レイアウトの更新 wxButton* btn = (wxButton*)FindWindowByName("myButton"); btn->Bind(wxEVT_BUTTON, &MyFrame::OnClick, this); // ボタンのクリックイベント btn->Bind(wxEVT_DESTROY, &MyFrame::OnBtnDestroy, this); // ユーザー定義のデータを破棄するための処理を追加 } MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(NULL, wxID_ANY, title, pos, size) { // CallAfter : 現在処理中のイベントが終わったらPostCreateを実行 // コンストラクタはウィンドウ生成イベント扱い CallAfter(&MyFrame::PostCreate); }
// ボタンのクリックイベント void OnClick(wxCommandEvent& event) { wxButton* btn = (wxButton*)event.GetEventObject(); myoption_data* data = (myoption_data*)btn->GetClientData(); wxString text = wxString::Format("%s %d", data->str, data->attr); wxMessageBox(text); }
// ユーザー定義のデータを持つボタンの破棄イベント void OnBtnDestroy(wxWindowDestroyEvent& event) { wxButton* btn = (wxButton*)event.GetEventObject(); myoption_data* data = (myoption_data*)btn->GetClientData(); delete data; }
};