スポンサーリンク

wxWidgetsで.xrcファイルからデザインを読み込んで適用(4)独自のタグを読み込む

.xrcファイルはxml形式なので、独自のタグを入れられる。ただしそれを解析する機能がデフォルトではないので、ハンドラを用意する必要がある。

.xrcファイル

.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>

include

// 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;

    }
};

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: