1. 程式人生 > >MFC建立的MDI程式 新建一個子文件 主視窗標題自動會被追加上子文件的名字 取消此功能

MFC建立的MDI程式 新建一個子文件 主視窗標題自動會被追加上子文件的名字 取消此功能

overwrite CMainFrame::OnUpdateFrameTitle

void CMainFrame::OnUpdateFrameTitle(BOOL bAddToTitle)
{
    CMDIFrameWnd::OnUpdateFrameTitle(bAddToTitle);

    ::SetWindowText(m_hWnd,m_strTitle);

}

現在很多應用程式的介面基本是用配置檔案來規劃介面的,在這個時候就得學會自定義選單欄和工具欄之類的。


      VS Feature Pack是為微軟新推出的介面庫(聽說是買BCG的授權,然後對之進行改造的),其中的主要的介面類可以和BCG的介面類可以對應起來,類的使用和BCG的也大同小異。但是有些做法還是很不一樣,比如這次我要提到的自定義選單欄。這裡的自定義選單欄是指去除系統預設的選單欄,然後動態建立選單欄。今天摸索了一下,大致搞清楚了(說實話,這方面網上的資料很少)。


      首先我們新建一個MFC的單文件工程:DynamicMenu,基本設定如下:

        這裡要提一下的是VS Feature Pack的應用程式其中的選單欄操作主要由CMFCMenuBar來負責。因此下面的編碼也主要針對該類來進行。


       首先我們實現編碼實現刪除預設的所有系統選單項,其程式碼如下:


view plaincopy to clipboardprint?
// 刪除預設的所有系統選單項    
static void DelAllMenu(HMENU hMenu)     
{     
    int Menucount = ::GetMenuItemCount(hMenu);     
    for (int i = Menucount-1;i>-1;i--)     
    {     
        ::DeleteMenu(hMenu,i, MF_BYPOSITION);     
    }       
}    
// 刪除預設的所有系統選單項 
static void DelAllMenu(HMENU hMenu) 

int Menucount = ::GetMenuItemCount(hMenu); 
for (int i = Menucount-1;i>-1;i--) 

   ::DeleteMenu(hMenu,i, MF_BYPOSITION); 
}    
}


然後我們定義兩個選單資源ID:


view plaincopy to clipboardprint?
#define ID_NEW_MENUBAR_OPEN     5000   
#define ID_NEW_MENUBAR_SAVE     5001 
#define ID_NEW_MENUBAR_OPEN 5000
#define ID_NEW_MENUBAR_SAVE 5001


為CMainFrame類新增一個建立選單欄的成員函式:


view plaincopy to clipboardprint?
void CMainFrame::NewMenuBar()   
{   
    CMenu menu;   
    menu.CreateMenu();   
    CString strMenu;   
    strMenu = _T("開啟檔案");   
    menu.AppendMenu(MF_ENABLED|MF_STRING,ID_NEW_MENUBAR_OPEN,strMenu);   
    strMenu = _T("儲存檔案");   
    menu.AppendMenu(MF_ENABLED|MF_STRING,ID_NEW_MENUBAR_SAVE,strMenu);   
    CString strMenuBarTitle;   
    strMenuBarTitle = _T("檔案");;   
    m_wndMenuBar.InsertButton (CMFCToolBarMenuButton (0, menu, -1,strMenuBarTitle));   

void CMainFrame::NewMenuBar()
{
CMenu menu;
menu.CreateMenu();
CString strMenu;
strMenu = _T("開啟檔案");
menu.AppendMenu(MF_ENABLED|MF_STRING,ID_NEW_MENUBAR_OPEN,strMenu);
strMenu = _T("儲存檔案");
menu.AppendMenu(MF_ENABLED|MF_STRING,ID_NEW_MENUBAR_SAVE,strMenu);
CString strMenuBarTitle;
strMenuBarTitle = _T("檔案");;
m_wndMenuBar.InsertButton (CMFCToolBarMenuButton (0, menu, -1,strMenuBarTitle));
}


我們在CMainFrame類的OnCreate函式呼叫這個函式,這裡只給出部分程式碼:


view plaincopy to clipboardprint?
if (!m_wndMenuBar.Create(this))   
{   
    TRACE0("Failed to create menubar\n");   
    return -1;      // fail to create   
}   
m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);   
HMENU hm = m_wndMenuBar.GetDefaultMenu();   
// 刪除預設選單欄   
if (NULL!=hm)     
{     
    DelAllMenu(hm);     
}     
// 建立新的選單欄   
NewMenuBar(); 
if (!m_wndMenuBar.Create(this))
{
   TRACE0("Failed to create menubar\n");
   return -1;      // fail to create
}
m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
HMENU hm = m_wndMenuBar.GetDefaultMenu();
// 刪除預設選單欄
if (NULL!=hm) 

   DelAllMenu(hm); 

// 建立新的選單欄
NewMenuBar();


現在我們看看效果如何,如下圖:


        我們發現預設選單欄去掉了,但是新的選單欄並沒有出來。到網上搜資料,但是並沒有搜到適用的,看了看Visual C++ 2008 Feature Pack Demo中提供的DynamicMenu的原始碼,瞭解了要增加AFX_WM_RESETMENU訊息的處理函式,在函式裡呼叫建立選單欄,具體增加的程式碼如下:


view plaincopy to clipboardprint?
// MainFrm.h : interface of the CMainFrame classafx_msg    
// AFX_WM_RESETMENU訊息的處理函式宣告   
LRESULT OnResetMenu(WPARAM,LPARAM);    
// MainFrm.cpp : implementation of the CMainFrame class   
// 訊息巨集中增加   
ON_REGISTERED_MESSAGE(AFX_WM_RESETMENU,&CMainFrame::OnResetMenu)   
LRESULT CMainFrame::OnResetMenu(WPARAM,LPARAM)   
{   
    NewMenuBar();   
    return 0;   

// MainFrm.h : interface of the CMainFrame classafx_msg 
// AFX_WM_RESETMENU訊息的處理函式宣告
LRESULT OnResetMenu(WPARAM,LPARAM); 
// MainFrm.cpp : implementation of the CMainFrame class
// 訊息巨集中增加
ON_REGISTERED_MESSAGE(AFX_WM_RESETMENU,&CMainFrame::OnResetMenu)
LRESULT CMainFrame::OnResetMenu(WPARAM,LPARAM)
{
NewMenuBar();
return 0;
}


       我們再刪除程式的登錄檔相關項重新編譯(使用VS Feature Pack開發刪除登錄檔這一項非常重要,Feature Pack的介面設計儲存思路實際上和BCG是一樣的,把上次使用者設定的介面配置資訊都儲存在登錄檔,如果不刪除登錄檔相關項,往往不能更新介面,登錄檔相關項一般在HKEY_CURRENT_USER\Software\Local AppWizard-Generated Applications\你的工程名稱(英文版VS),HKEY_CURRENT_USER\Software\應用程式嚮導生成的本地應用程式\你的工程名稱(中文版VS))。


     我們再看看效果,如下圖:

     你可能會發現選單是灰的,那是沒有新增選單的命令響應函式的緣故。本文的編譯環境為:Windows XP + sp3, VS C++ 2008 + sp1。

      後來查了一下MSDN對AFX_WM_RESETMENU訊息的解釋,如下:

參考文獻:

1. AFX Messages

在VC6.0和VS2010裡面動態新增選單項是不一樣的,檢視MSDN文件可知,VS2010採用的是MFC9.0版,其中有很多新增的項具體資訊請檢視http://msdn.microsoft.com/en-us/library/ws8s10w4.aspx,本文就根據自己的測試詳細的比較一下二者的區別:

1.在VC6.0裡面動態新增一個子選單項:

在CMainFrame::OnCtreate()中新增程式碼,另外要在Resource.h裡面新增#define ID_MENU_ADDMENUITEM    32773

CMainFrame::OnCtreate(){

//下面是新增的程式碼

CMenu *pMenu=AfxGetMainWnd()->GetMenu(); 
CMenu *pmSub=pMenu->GetSubMenu(1); 
pmSub->AppendMenu(MF_STRING,ID_MENU_ADDMENUITEM,L"Add Menu &Item");

}//效果是在“Edit”選單最下面添加了一個"Add Menu Item"子項


2.在VS2010裡面新增一個子選單項:

要對CMainFrame類的OnShowPopupMenu()進行過載,另外要在Resource.h裡面新增#define IDS_EDIT_MYITEM_1    32773

BOOL CMainFrame::OnShowPopupMenu(CMFCPopupMenu* pMenuPopup) 

    // TODO: Add your specialized code here and/or call the base class

    int iIndex = -1; 
    if (!CMFCToolBar::IsCustomizeMode()&&(iIndex=pMenuPopup->GetMenuBar()->CommandToIndex(ID_EDIT_PASTE))>=0) 
    { 
        pMenuPopup->InsertSeparator(iIndex+1); 
        pMenuPopup->InsertItem(CMFCToolBarMenuButton(IDS_EDIT_MYITEM_1,NULL,-1,_T("&MyItem 1")),iIndex+2); 
    }   //使用CommandToIndex()來獲得選單項的索引,然後根據索引來確定子選單項的新增位置 
    return CFrameWndEx::OnShowPopupMenu(pMenuPopup); 
}//效果是在“Edit”選單最下面添加了一個分割線和一個"MyItem 1"子項

效果如圖,因為還沒有為其新增處理函式,所以呈灰色:


給新增的子選單項新增訊息處理函式:

在MainFrame.h裡面新增訊息處理函式宣告:

   class CMainFrame : public CFrameWnd{

//…

protected:

afx_msg void OnEditMyItem1 ();

}

然後在MainFrame.cpp訊息對映裡面新增訊息對映項:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 
     //…

    ON_COMMAND(IDS_EDIT_MYITEM_1, OnEditMyItem1) 
END_MESSAGE_MAP()

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

CMFCMenuBar的繼承關係:

CObject

    CCmdTarget

           CWnd

                   CBasePane

                          CPane

                                 CMFCBaseToolBar

                                         CMFCToolBar

                                                   CMFCMenuBar

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++