乐者为王

Do one thing, and do it well.

XRC和动态子菜单

1、什么是XRC

XRC是基于XML的资源系统。它的基本出发点是将界面布局和程序逻辑分离,即将界面布局代码保存在分离的XML文件中,在程序中不涉及控件的创建和布局,只需要加载相应的资源并处理事件绑定即可。

2、XRC文件格式

1
2
3
4
5
6
<?xml version="1.0"?>
<resource version="2.3.0.1">
    <object class="wxFrame" name="ID_MAIN_FRAME">
        <size>200, 300</size>
    </object>
</resource>

3、XRC文件中菜单资源的相关属性

属性 描述
wxMenuBar style Menu bar style: wxMB_DOCKABLE
wxMenu style Menu style: wxMENU_TEAROFF
label Text: label of the menu.
help Text: displayed help string.
wxMenuItem style Menu style: wxMENU_TEAROFF
label Text: label of the menu.
accel Text: accelerator associated to this item ( Alt-X for example ).
help Text: displayed help string.
radio bool value(0/1): 1 if this item is a radio menu item.
checkable bool value(0/1): 1 if this item is a check menu item.
enabled bool value(0/1): 1 if this item is initially enabled.
checked bool value(0/1): 1 if this (check) item is initially checked.
bitmap Text: path to a bitmap to draw at the left of the item.

4、使用XRC创建菜单

创建一个包含菜单布局信息的XML资源文件MenuBar.xrc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8" ?>
<resource version="2.3.0.1" xmlns="http://www.wxwindows.org/wxxrc">
    <object class="wxMenuBar" name="ID_MENUBAR">
        <object class="wxMenu" name="ID_MENU_FILE">
            <label>&File</label>
            <object class="wxMenuItem" name="wxID_CLOSE">
                <label>E&xit</label>
                <accel>Ctrl+Q</accel>
                <help>Quit the application</help>
            </object>
        </object>
        <object class="wxMenu" name="ID_MENU_VIEW">
            <label>&View</label>
        </object>
        <object class="wxMenu" name="ID_MENU_TOOLS">
            <label>&Tools</label>
            <object class="wxMenuItem" name="wxID_OPTIONS">
                <label>&Options...</label>
            </object>
        </object>
        <object class="wxMenu" name="ID_MENU_HELP">
            <label>&Help</label>
            <object class="wxMenuItem" name="wxID_CHECKFORUPDATES">
                <label>Check for &Updates...</label>
            </object>
            <object class="separator" />
            <object class="wxMenuItem" name="wxID_ABOUT">
                <label>&About...</label>
            </object>
        </object>
    </object>
</resource>

加载资源文件:

1
2
3
4
5
6
bool MainApp::OnInit()
{
    wxXmlResource* pResource = wxXmlResource::Get();
    pResource->AddHandler(new wxMenuBarXmlHandler);
    pResource->AddHandler(new wxMenuXmlHandler);
    pResource->Load(wxT("resources/MenuBar.xrc"));

初始化资源文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MainFrame::MainFrame(const wxString& title) : wxFrame(NULL, wxID_ANY, title)
{
    m_menuBar = NULL;
    InitMenuBar();
}

bool MainFrame::InitMenuBar()
{
    if (m_menuBar)
    {
        SetMenuBar(NULL);
        delete m_menuBar;
    }
    // Initialize the resource system
    m_menuBar = wxXmlResource::Get()->LoadMenuBar(wxT("ID_MENUBAR"));
    if (!m_menuBar)
    {
        wxLogError(wxT("Cannot load main menu from resource file"));
        return false;
    }
    SetMenuBar(m_menuBar);
    return true;
}

5、在XRC菜单上添加动态子菜单

在资源文件中添加一个新的菜单项(wxID_LANGUAGES):

1
2
3
4
5
6
7
8
9
10
11
<object class="wxMenu" name="ID_MENU_VIEW">
    <label>&View</label>
    <object class="wxMenu" name="wxID_LANGUAGE">
        <label>&Language</label>
        <object class="wxMenuItem" name="wxID_LANGUAGES">
            <label>Get Additional/Update language pack</label>
            <help>Downloading Additional/Update language pack</help>
        </object>
        <object class="separator" />
    </object>
</object>

创建动态子菜单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Initialize the resource system
m_menuBar = wxXmlResource::Get()->LoadMenuBar(wxT("ID_MENUBAR"));
if (!m_menuBar)
{
    wxLogError(wxT("Cannot load main menu from resource file"));
    return false;
}
/*
 * 这里很奇怪,在XRC文件wxID_LANGUAGE的类型明明是wxMenu,可在这里确只能用wxMenuItem。
 * 查看wxWidgets源代码发现XRC系统只会把最上层的class为wxMenu的object创建为wxMenu对象。
 * 其它的则都被创建成了wxMenuItem对象。
 */
// 使用XRCID方法获取控件ID,创建动态子菜单
wxMenuItem* menuItem = m_menuBar->FindItem(XRCID("wxID_LANGUAGE"));
if (menuItem)
{
    wxMenu* subMenu = menuItem->GetSubMenu();
    subMenu->AppendRadioItem(wxID_LANGUAGE_LOWEST + 1, wxT("English"));
    subMenu->AppendRadioItem(wxID_LANGUAGE_LOWEST + 2, wxT("Chinese(Simplified)"));
}
SetMenuBar(m_menuBar);
return true;

代码下载

Comments