天天看點

在MFC程式中使用XML檔案配置工具欄

現在我發現使用Visual Studio的資源編輯器進行編輯資源有着諸多的不便:首先是任何資源的變動一般變動代碼,不利于系統維護,其次Visual Studio的資源編輯器的本身的功能有限,也不利于界面美化,三是不利于人員分工,開發人員既要忙實作功能,又要忙準備好的界面素材。對界面實作檔案配置化正是解決上面問題的好方法。這次我實作了使用XML檔案配置工具欄。這裡所謂配置就是工具欄的界面資訊如工具欄标題、按鈕圖檔、是否為分隔符都在XML檔案儲存,程式通過解析XML檔案來擷取工具欄資訊來建立工具欄。這樣一旦發現界面不合适可以随時修改配置檔案,同時利于人員分工。

具體的做法如下:

1.       在工程的輸出目錄下有一個SysConfig.xml,作為系統配置檔案。其中關于工具欄的配置部分如下:

在MFC程式中使用XML檔案配置工具欄

       <AppToolbar valid="1" caption="基礎工具">

            <ToolButton file="Add.bmp" />

            <ToolButton separator="true" />

            <ToolButton file="Benchmark.bmp" />

            <ToolButton file="Comment.bmp" />

            <ToolButton file="Convert.bmp" />

            <ToolButton file="Delete.bmp" />

            <ToolButton file="Exit.bmp" />

        </AppToolbar>

在MFC程式中使用XML檔案配置工具欄

簡單解釋一下上面的節點意義:valid表示工具欄是否有效,caption表示工具欄标題,file節點為工具欄按鈕所貼圖檔,separator表示按鈕是分隔符。

2.       通過解析XML檔案擷取工具欄資訊來建立工具欄。首先在CMainFrame類添加兩個資料成員:

在MFC程式中使用XML檔案配置工具欄

      /**

    * \brief 工具欄對應的圖像清單。

    */

    CImageList        m_imgToobar;

    /**

    * \brief 系統配置檔案解析器,具體看我上傳的代碼。

    CXmlParse m_SysSetting;

在MFC程式中使用XML檔案配置工具欄

     然後實作如下函數:

在MFC程式中使用XML檔案配置工具欄

    /*!

    *  \brief 擷取exe所在的檔案夾。

    *

    *  \param [in][out]strBinPath exe程式所在的檔案夾。

    *  \return 無。

    void CMainFrame::GetOutputPath(string &strBinPath)

{

    TCHAR szModulePath[_MAX_PATH];

    ::GetModuleFileName(NULL,szModulePath,_MAX_PATH);

    strBinPath = szModulePath;

    strBinPath = strBinPath.substr(0,strBinPath.rfind('\\')+1);

}

    *  \brief 解析系統配置檔案,擷取工具欄資訊。

    *  \param [in][out]MyToolbar 工具欄資訊。

void CMainFrame::ParseXml(ToolBar &MyToolbar)

    string strBinPath;

    GetOutputPath(strBinPath);

    string strXmlPath = strBinPath + string(_T("SysConfig.xml"));

    m_SysSetting.OpenXml(strXmlPath);

    m_SysSetting.GetToolbarInfo(MyToolbar);

    *  \brief 根據工具欄圖檔資訊加載工具欄圖像清單。

    *  \param [in]MyToolbar 工具欄資訊。

    *  \return 是否成功。true為成功,false表示失敗。

BOOL CMainFrame::LoadImageList(ToolBar &MyToolbar)

    // 擷取按鈕圖檔的個數

    int nBmpNum = MyToolbar.m_MenuItemVec.size();

    HBITMAP        hBitmap                = NULL;

    // 打開所有位圖,将其加進圖像清單

    for(int i=0; i<nBmpNum; ++i)

    {

        if (MyToolbar.m_MenuItemVec[i].m_bIsSeparator)

        {

            continue;

        }

        string strBinPath;

        GetOutputPath(strBinPath);

        string strBmpPath = strBinPath + string(_T("Toolbar\\"));

        strBmpPath = strBmpPath +    MyToolbar.m_MenuItemVec[i].m_strBmpName;

        hBitmap = (HBITMAP)LoadImage(AfxGetResourceHandle(),strBmpPath.c_str(), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR|LR_LOADFROMFILE);

        if (NULL==hBitmap)

            return FALSE;

        CBitmap        bmp;

        bmp.Attach(hBitmap);

        m_imgToobar.Add(&bmp, RGB(0, 0, 0));

        bmp.DeleteObject();

    }

    return TRUE;

    *  \brief 設定工具欄按鈕風格。

BOOL CMainFrame::SetStyleToolbar(ToolBar &MyToolbar)

    CToolBarCtrl&    tbc    = m_wndToolBar.GetToolBarCtrl();

    // 删除之前的按鈕

    while(tbc.DeleteButton(0));

    // 設定目前圖像清單

    tbc.SetImageList(&m_imgToobar);

    int        i            = 0;

    int        nBtnNum    = MyToolbar.m_MenuItemVec.size();

    UINT nBtnID = SYS_COMMAND_BEGIN;

    int nImgIndex = 0;

    // 根據按鈕屬性逐個添加按鈕

    for(i=0; i<nBtnNum; ++i)

            TBBUTTON tb = {-1,0,TBSTATE_ENABLED,TBSTYLE_SEP,0,0};

            tbc.AddButtons(1, &tb);

        else

            TBBUTTON tb = {nImgIndex,nBtnID,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0};

            nImgIndex++;

            nBtnID++;

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

        return -1;

    /*

    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

        | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

        !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))*/

    // 解析系統配置檔案,擷取位圖資訊

    ToolBar AppToolbar;

    ParseXml(AppToolbar);

    if(!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD|WS_VISIBLE|CBRS_TOP

        |CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC))

        TRACE0("未能建立工具欄\n");

        return -1;      // 未能建立

    m_wndToolBar.SetWindowText(AppToolbar.m_strCaption.c_str());

    // 建立圖像清單

    m_imgToobar.Create(32, 32, ILC_COLOR32|ILC_MASK, 0, 0);

    if(LoadImageList(AppToolbar))

        // 添加工具欄按鈕

         SetStyleToolbar(AppToolbar);

    // 設定工具欄按鈕大小

    m_wndToolBar.SetSizes(CSize(32+7, 32+6), CSize(32, 32));

    if (!m_wndStatusBar.Create(this) ||

        !m_wndStatusBar.SetIndicators(indicators,

          sizeof(indicators)/sizeof(UINT)))

        TRACE0("未能建立狀态欄\n");

    // TODO: 如果不需要工具欄可停靠,則删除這三行

    m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

    EnableDocking(CBRS_ALIGN_ANY);

    DockControlBar(&m_wndToolBar);

    return 0;

在MFC程式中使用XML檔案配置工具欄

      為使工具欄處于有效狀态,還得添加一個簡單的消息處理函數,簡單如下:

在MFC程式中使用XML檔案配置工具欄

    *  \brief 工具欄按鈕響應事件。

    *  \param [in]nID 工具欄按鈕ID。

void CMainFrame::OnButton(UINT nID)

   switch (nID)

   {

   // SYS_COMMAND_BEGIN為工具欄按鈕的起始ID值

   case SYS_COMMAND_BEGIN:

       AfxMessageBox(_T("你單擊的是第一個按鈕"));

          break;

   case SYS_COMMAND_BEGIN+1:

       AfxMessageBox(_T("你單擊的是第二個按鈕"));

       break;

   case SYS_COMMAND_BEGIN+2:

       AfxMessageBox(_T("你單擊的是第三個按鈕"));

   case SYS_COMMAND_BEGIN+3:

       AfxMessageBox(_T("你單擊的是第四個按鈕"));

   case SYS_COMMAND_BEGIN+4:

       AfxMessageBox(_T("你單擊的是第五個按鈕"));

   case SYS_COMMAND_BEGIN+5:

       AfxMessageBox(_T("你單擊的是第六個按鈕"));

   default:

   }

在MFC程式中使用XML檔案配置工具欄

開發環境為Visual C++ 2005 + sp1,Win XP + sp3。程式效果圖如下:

     工程源碼已上傳到聯合程式開發網,連結為:

參考文獻: