wxWidgets的多文档界面(MDI)

MDI

MDI是多文档界面的简称。在这种界面下,所有子窗口都在父窗口之内,子窗口之间相互独立,可以在父窗口内活动和排列,也可以放大后占据父窗口的所有空间(遮盖其他子窗口)。

MDI界面中,主要的两个类是wxMDIParentFrame和wxMDIChildFrame。wxMDIParentFrame代表MDI父窗口,wxMDIChildFrame代表MDI子窗口。一般MDI程序需要一个继承自wxMDIParentFrame的对象作为主窗口,主窗口可以包含多个继承自wxMDIChildFrame的子窗口。

一个MDI窗口程序例子如下。该程序可以通过单机工具栏按钮创建子窗口,运行效果如下:
wxWidgets的多文档界面(MDI)_第1张图片
(1)主窗口类代码如下:

/// MainFrame.h

#pragma once

#include "wxInc.h"

class MainFrame : public wxMDIParentFrame
{
    DECLARE_EVENT_TABLE();

public:
    MainFrame(void);
    ~MainFrame(void);

public:
    void CreateBars();
    void CreateChild(wxCommandEvent & evt);
};
/// MainFrame.cpp

#include "MainFrame.h"

enum {
    ID_ITEM_1 = wxID_HIGHEST + 1,
    ID_ITEM_2,
    ID_ITEM_3,
    ID_ITEM_4,
};


BEGIN_EVENT_TABLE(MainFrame, wxMDIParentFrame)
    EVT_TOOL(ID_ITEM_3, CreateChild)
END_EVENT_TABLE()

MainFrame::MainFrame() : wxMDIParentFrame(NULL, wxID_ANY, wxT("main window"))
{
    /// 创建菜单栏、工具栏和状态栏.
    CreateBars(); 
}

MainFrame::~MainFrame()
{
}

void MainFrame::CreateBars()
{
    /// 1. 创建菜单栏
    wxMenuBar * menuBar = new wxMenuBar();

    wxMenu * menu1 = new wxMenu();
    menu1->Append(ID_ITEM_1, wxT("subitem 1-1"));
    menu1->Append(ID_ITEM_2, wxT("subitem 1-2"));
    menuBar->Append(menu1, wxT("item 1"));

    SetMenuBar(menuBar);

    /// 2. 创建工具栏
    wxToolBar * toolBar = new wxToolBar(this, wxID_ANY);
    toolBar->AddTool(ID_ITEM_3, wxT("button1"), wxArtProvider::GetBitmap(wxART_GO_BACK, wxART_TOOLBAR));
    toolBar->AddTool(ID_ITEM_4, wxT("button2"), wxArtProvider::GetBitmap(wxART_TIP, wxART_TOOLBAR));
    toolBar->Realize();  /// 在增加按钮后必须调用此函数
    SetToolBar(toolBar);    

    /// 3. 创建状态栏
    wxStatusBar * statusBar = CreateStatusBar(2);
}

void MainFrame::CreateChild(wxCommandEvent & evt)
{
    /// 创建子窗口(自动显示).
    wxMDIChildFrame * childWnd = new wxMDIChildFrame(this, wxID_ANY, wxT("child window"));
}

(2)主程序代码如下:

/// MyApp.h
#pragma once

#include "wxInc.h"

class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};

DECLARE_APP(MyApp)
/// MyApp.cpp

#include "MyApp.h"

#include "MainFrame.h"

IMPLEMENT_APP(MyApp)

    bool MyApp::OnInit()
{
    MainFrame * mainWnd = new MainFrame();
    SetTopWindow(mainWnd);
    mainWnd->Show(true);

    return true;
}

Tab风格的MDI(Tab-based MDI)

通过AUI,也可实现Tab风格的MDI,即每个子窗口占据父窗口的全部空间,子窗口通过标签进行选择和显示(类似Visual Studio的风格)。
在AUI框架下,实现Tab风格MDI程序需要两个步骤:

  • wxAuiMDIParentFrame替换wxMDIParentFrame,用wxAuiMDIChildFrame替换wxMDIChildFrame
  • 完成AUI管理器(wxAuiManager)的初始化、设置和清理工作。

程序的其他部分可以基本保持不变。

下面实现了一个Tab风格的MDI窗口,程序运行效果如下:
wxWidgets的多文档界面(MDI)_第2张图片

只需要改动主窗口代码即可。主窗口代码如下:

/// MainFrame.h

#pragma once

#include "wxInc.h"

class MainFrame : public wxAuiMDIParentFrame
{
    DECLARE_EVENT_TABLE();

public:
    MainFrame();
    ~MainFrame();

private:
    void CreateBars();
    void CreatePanes();

private:
    void OnTest1(wxCommandEvent & evt);
    void OnClose(wxCloseEvent & evt);

private:
    wxAuiManager    mAuiMgr;
};
/// MainFrame.cpp

#include "MainFrame.h"

enum {
    ID_TEST1 = wxID_HIGHEST + 1,
};

BEGIN_EVENT_TABLE(MainFrame, wxAuiMDIParentFrame)
    EVT_MENU(ID_TEST1, OnTest1)
    EVT_CLOSE(OnClose) /// 注册窗口关闭消息处理函数
END_EVENT_TABLE()

MainFrame::MainFrame()
    : wxAuiMDIParentFrame(NULL, wxID_ANY, wxT("main window"),
    wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE)
{
    mAuiMgr.SetManagedWindow(this);

    CreateBars();
    CreatePanes();

    //mAuiMgr.Update();
}

MainFrame::~MainFrame()
{
    mAuiMgr.UnInit();
}

void MainFrame::CreateBars()
{
    wxMenuBar * menuBar = new wxMenuBar();
    wxMenu * menu1 = new wxMenu();
    menu1->Append(ID_TEST1, wxT("item1"));
    menuBar->Append(menu1, wxT("File"));

    SetMenuBar(menuBar);

    wxToolBar * toolBar = new wxToolBar(this, wxID_ANY);
    toolBar->AddTool(ID_TEST1, wxT("test1"), wxArtProvider::GetBitmap(wxART_NEW, wxART_TOOLBAR));
    toolBar->Realize();
    SetToolBar(toolBar);

    CreateStatusBar(2);
}

void MainFrame::CreatePanes()
{

}

void MainFrame::OnTest1(wxCommandEvent & evt)
{
    wxAuiMDIChildFrame * childWnd = new wxAuiMDIChildFrame(this, wxID_ANY, wxT("child"));

}

void MainFrame::OnClose(wxCloseEvent & evt)
{
    /// 处理窗口关闭消息
    wxAuiNotebook * notebook = GetNotebook();
    if (notebook)
    {
        /// 关闭所有子窗口.
        notebook->DeleteAllPages();
    }

    evt.Skip();
}

需要注意的是,当还有子窗口存在时,退出程序有时会抛出异常,而子窗口全部关闭则无此现象。(Visual Studio 2013有此现象,Visual Studio 2010则无 )
所以,通过模拟正常工作时的退出流程,在程序关闭时,通过处理窗口关闭消息(EVT_CLOSE),主动关闭所有子窗口,可以避免出现异常。

EVT_CLOSE的处理函数OnClose代码如下。

void MainFrame::OnClose(wxCloseEvent & evt)
{
    wxAuiNotebook * notebook = GetNotebook();
    if (notebook)
    {
        notebook->DeleteAllPages();
    }

    evt.Skip();
}

你可能感兴趣的:(wxWidgets的多文档界面(MDI))