天天看點

MFC 菜單程式設計 -- 總結 .

菜單結構

一個菜單欄可以有若幹個子菜單,而一個子菜單又可有若幹個菜單項。

對于菜單欄的子菜單,由左至右從0開始索引。

對于特定的子菜單的菜單項,由上至下建立從0開始的索引。

通路子菜單和菜單項,均可通過其索引或辨別進行。

對于在視窗客戶區右鍵彈出的菜單,如果彈出菜單歸屬View 類視窗,則菜單項隻能響應View 和Doc 類消息點選。

如果彈出菜單歸屬架構視窗,彈出菜單上的消息的路由遵循View -DOC-MainFrame-APP的響應順序 。

菜單的相關重要函數

CMenu*    GetMenu( ) ;                  // 得到菜單指針

CMenu*    GetSubMenu( ) ;           // 得到子菜單指針,也就是彈出菜單指針

UINT CheckMenuItem( );              // 将菜單項加上或去掉√(對号)标記

a.如果第一個參數是ID号,    第二個參數必須是MF_BYCOMMAND | MF_CHECKED的組合

b.如果第一個參數是索引号, 第二個參數必須是MF_BYPOSITION   | MF_CHECKED的組合

BOOL SetDefaultItem();                // 設定預設菜單,也就是将菜單項粗體顯示

a.如果第一個參數是索引号,第二個參數必須是true

b.如果第一個參數是ID号,第二個參數必須是false

*注 :一個子菜單最多隻能有一個預設菜單項

BOOL SetMenuItemBitmaps( );      // 設定位圖示記,标記大小為13*13像素

a.如果第一個參數是ID号,第二個參數必須是MF_BYCOMMAND

b.如果第一個參數是索引号,第二個參數必須是MF_BYPOSITION

,第三個參數是沒有選中時的位圖,第四個參數是标記時的位圖

UINT EnableMenuItem();                //使菜單項有效,無效,或變灰

a.如果第一個參數是ID号,第二個參數必須是MF_BYCOMMAND 和有效,無效,或變灰 的組合

b.如果第一個參數是索引号,第二個參數必須是MF_BYPOSITION 和有效,無效,或變灰 的組合

*注 :若讓此函數生效,必須在mainfrm構造函數中添加:m_bAutoMenuEnable =false,

此時,其他變灰的菜單項也就恢複為不變灰狀态了,會有副作用的

BOOL SetMenu( CMenu* pMenu );  //在目前視窗上設定新菜單或移除菜單。

如果參數為0,則是移除菜單。

自己建立菜單{CMenu menu;menu.LoadMenu(IDR_MENU1);

SetMenu(&menu);menu.Detach();}

HMENU Detach( );  // 如果将CMenu 對象設定為局部對象,使用Detach()從menu對象中分離視窗菜單句柄,進而當menu對象析構的時候視窗菜單資源不随之銷毀

菜單的相關操作的實作方法

a.添加對号标記:

方法一:   GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED );                          //通過索引

方法二:   GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_CHECKED );     //通過ID

b.設定預設菜單項:

每個子菜單最多隻能有一個預設菜單項

方法一: GetMenu()->GetSubMenu(0)->SetDefaultItem(1,true);                             //通過索引

方法二: GetMenu( )->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN,false);     //通過ID

c.添加圖形标記:

方法一:通過ID

CBitmap bitmap;       //必須設定為全局對象

bitmap.LoadBitmap(IDB_BITMAP1);

GetMenu( )->GetSubMenu(0)->SetMenuItemBitmaps(ID_FILE_NEW,MF_BYCOMMAND,&bitmap,&bitmap);

方法二:通過索引

GetMenu( )->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION ,&bitmap,&bitmap);

d.使菜單無效,變灰

//必須在構造函數中添加:   m_bAutoMenuEnable = false;

GetMenu( )->GetSubMenu(0)->EnableMenuItem(ID_FILE_OPEN,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);

e.移除菜單

SetMenu(0);

f.添加菜單

CMenu menu;

menu.LoadMenu(IDR_MAINFRAME);

SetMenu(&menu);

menu.Detach();

圖形标記大小

系統獲得位圖示記的大小:

CString str;

str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK));

MessageBox(str);

指令更新機制

菜單的UPDATE_COMMAND_UI消息響應

{

     pCmdUI->Enable(false);       // true和false 來設定能否使用或變灰

     pCmdUI->SetCheck(true);   // true和false 來設定标記

     pCmdUI->SetText(“cut”);    //改變菜單項文本内容

}

動态建立菜單

先定義幾個常量:

#define IDM_MENU0 0

#define IDM_MENU1 1

#define IDM_MENU2 2

#define IDM_MENU3 3

#define IDM_ITEM0 10

#define IDM_ITEM1 11

#define IDM_ITEM2 12

#define IDM_ITEM3 13

#define IDM_ITEM4 14

#define IDM_ITEM5 15

#define IDM_ITEM6 16

// 在最後一個菜單項後面添加菜單項

BOOL AppendMenu ( UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL);

BOOL AppendMenu ( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );

// 插入菜單項

BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL );

BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp );

// 移除菜單項

BOOL RemoveMenu( UINT nPosition, UINT nFlags );

// 删除菜單項

BOOL DeleteMenu( UINT nPosition, UINT nFlags );

一 、建立非Popup類型菜單,不使用資源。

(一)建立非下拉菜單。

1。在視窗類的OnCreate函數裡建立CMenu對象。如果是建立運用程式主架構視窗

的話,也可以在InitInstance()函數裡。

2。聲明一個CMenu對象:CMenu MyMenu;

3。調用MyMenu.CreateMenu()或MyMenu.LoadMenu()

4。調用若幹次MyMenu.AppendMenu()或MyMenu.InsertMenu(),每調用一次建立一

個菜單項。

5。調用MyMneu.SetMenu()将菜單Attach到視窗上。

6。調用MyMenu.Detach()。

例子:

int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )

     CMenu MyMenu;

     MyMenu.CreateMenu();

     MyMenu.AppendMenu(MF_STRING,IDM_MENU0,"檔案");

     MyMenu.AppendMenu(MF_STRING,IDM_MENU1,"編輯");

     MyMenu.AppendMenu(MF_STRING,IDM_MENU2,"檢視");

     MyMenu.AppendMenu(MF_STRING,IDM_MENU3,"幫助");

     MyMenu.InsertMenu(IDM_MENU2,MF_BYCOMMAND,IDM_ITEM0,"有關");

     this->SetMenu(&MyMenu);

     MyMenu.Detach();

     return 0;

}//各個函數的細節就不講解了,看聯機幫助是最好的。

這個方法是先把菜單建立好後再貼到視窗上去,然後用Detach()使菜單和MyMenu對象脫離關系,因為MyMenu對象馬上就要超出作用域了,這一步是必須的。

(二)建立下拉菜單,不使用資源。

    這種菜單當滑鼠移動到菜單條目上面點選時不是去執行某段程式,而是彈出

一個下拉菜單。這需要用前面的方法建立兩個菜單。第一個是滑鼠未點選時看到

的那個菜單,另一個就是扮演下拉菜單的菜單。例子:

        CMenu MyMenu0,MyMenu1;

        //下面這幾條建立下拉菜單

        MyMenu1.CreateMenu();

        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM0,"拷貝");

        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM1,"剪切");

        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM2,"粘貼");

        MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");

        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM4,"全選");

        MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM5,"");

        MyMenu1.AppendMenu(MF_STRING,IDM_ITEM6,"删除");

        //下面這兩條建立滑鼠未點選時看到的那個菜單

        //其中第二句将下拉菜單張貼到第一個菜單上。

        MyMenu0.CreateMenu();

        MyMenu0.AppendMenu(MF_POPUP,(UINT)MyMenu1.m_hMenu,"編輯");

        this->SetMenu(&MyMenu0);//将菜單張貼到視窗上

        MyMenu0.Detach();//必須有

        MyMenu1.Detach();//必須有

        return 0;

二、建立Popup類型的菜單,也不用資源。

    很多程式裡,隻要用滑鼠右鍵點一下視窗客戶區,就會在滑鼠的位置彈出一

個菜單,這叫右鍵菜單。我們可以用CMenu類來制作。

    制作這種菜單比制作第一類菜單稍微複雜點。首先要在視窗類裡加個成員變

量:CMenu *MyMenu2;

    然後在視窗類的構造函數裡(或OnCreate()函數裡)加上建立菜單的語句,再

在析構函數裡加上銷毀菜單的語句,最後在OnRButtonDown()函數裡加上顯示菜單

的語句。

    建立菜單時,CMenu類對象應該用new來配置設定。

    例子:

CMyWnd::CMyWnd()

     //CMyWnd是從CWnd派生來的。

     //先把菜單建立起來。

     MyMenu2=new CMenu;

     MyMenu2->CreatePopupMenu();

     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM0,"拷貝");

     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM1,"剪切");

     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM2,"粘貼");

MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");

     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM4,"全選");

     MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,"");

     MyMenu2->AppendMenu(MF_STRING,IDM_ITEM5,"删除");

CMyWnd::~CMyWnd()

     MyMenu2->DestroyMenu();//銷毀菜單所占用的系統資源

     delete MyMenu2;//銷毀菜單類對象

void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point)

     RECT rect;

     GetWindowRect(&rect);

     //顯示菜單

     MyMenu2->TrackPopupMenu(TPM_RIGHTALIGN,point.x+rect.left,point.y+

rect.top,this,NULL);

繼續閱讀