本節學習了菜單編程方面的內容,包括靜態菜單操作和動態菜單操作兩大塊。
靜態菜單操作包括標記菜單,默認菜單,圖形菜單的實現原理及具體實現,快捷彈出菜單的實現方式及其命令響應函數的添加。
動態菜單操作主要包括:如何讓程序運行時產生新的子菜單和菜單項,以及如何手工地爲這些新產生的菜單項命令添加消息響應處理函數。
本節還實現瞭如何在頂層窗口,即框架類窗口中截獲對菜單命令的處理。
通過這節還應該瞭解Windows中消息的分類,以及菜單命令消息的路由過程,進一步熟悉Cstring類的應用。
靜態菜單操作
//1.標記菜單(2種方法)
//GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION| MF_CHECKED); //通過菜單項的索引設置一個標記菜單
//GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND| MF_CHECKED); //通過菜單項的標識設置一個標記菜單
//2.默認菜單
//GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE); //通過菜單項的索引設置一個默認菜單,最後一個參數爲TRUE
//GetMenu()->GetSubMenu(0)->SetDefaultItem(ID_FILE_OPEN,FALSE); //通過菜單項的標識設置一個默認菜單最後一個參數爲FALSE
//GetMenu()->GetSubMenu(0)->SetDefaultItem(5,TRUE); //設置打印菜單項時索引時5,不是4,因爲分隔欄在子菜單中是佔據索引位置的
//一個子菜單隻能有一個默認菜單項
//3.圖形標記菜單
/*CStringstr;
str.Format("x=%d,y=%d",GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK));
//CString類的Format函數可以按照一定的格式把內容格式化,然後將結果保存到CString類型的字符串對象中
//GetSystemMetrics()函數可以取得窗口上各種資源的尺寸,根據參數決定
//根據取得的尺寸信息可知,位圖大小應該是13*13;
MessageBox(str);*/
//m_bitmap.LoadBitmap(IDB_BITMAP1);
//GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);//運行程序發現不顯示位圖,
//原因在於位圖太大,只是顯示了位圖左上角的一小部分內容。
//4.禁用菜單項
//GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_BYPOSITION |MF_DISABLED | MF_GRAYED);
//GetMenu()->GetSubMenu(0)->EnableMenuItem(ID_FILE_OPEN,MF_BYCOMMAND| MF_DISABLED | MF_GRAYED);
//在構造函數中修改成員變量才能使這行代碼起作用m_bAutoMenuEnable= FALSE;
//MF_DISABLED| MF_GRAYED這兩個標誌一起使用
//5.移除和裝載菜單
//SetMenu(NULL);//移除
//裝載
//CMenumenu;
//menu.LoadMenu(IDR_MAINFRAME);
//SetMenu(&menu);
//menu是個局部變量,在程序運行時,點擊“打印預覽”,關閉“打印預覽”,再關閉程序,程序會報錯
//解決辦法是把menu定義爲CMainFram類的成員變量
//還可以用Detach函數把菜單句柄與這個菜單對象分離
//menu.Detach();
return0;
}
//m_bAutoMenuEnable= FALSE;
//一旦在CMainFrame類的構造函數中把成員變量m_bAutoMenuEnable =FALSE;後,就不需要對ON_UPDATE_COMMAND_UI
//或ON_COMMAND消息進行響應處理了,CMenu類的EnableMenuItem函數將能正常工作。
//但是在Menu程序編輯子菜單下的幾個菜單項不在以灰色顯示了,因爲m_bAutoMenuEnable= FALSE後,
//MFC就不在利用它的菜單命令更新機制去判斷哪個菜單可以使用,哪個菜單不能夠使用,所以其也就不能根據菜單項的狀態以不同的外觀
//來顯示。而菜單能否使用這些判斷操作,就需要我們自己去完成了
//說實話,命令更新機制講的不清楚啊!不明白啊!
//6.MFC菜單命令更新機制
//在消息映射中添加ON_UPDATE_COMMAND_UI宏來捕獲CN_UPDATE_COMMAND_UI消息
void CMainFrame::OnUpdateEditCut(CCmdUI*pCmdUI)
{
//TODO: Add your command update UI handler code here
//pCmdUI->Enable();//在這樣的消息中帶有一個指向CCmdUI對象的指針,可以用它調用相應的功能函數
//在工具欄中剪切的標識和菜單欄中的剪切標識是一樣,所以兩者都被啓用了。
if(2== pCmdUI->m_nIndex) //判斷當前是否是新建菜單項,實際中無需判斷,MFC調用菜單命令更新函數時,已經確定了特定的菜單項。
pCmdUI->Enable();
}
void CMainFrame::OnUpdateFileNew(CCmdUI*pCmdUI)
{
//TODO: Add your command update UI handler code here
//if(ID_FILE_NEW== pCmdUI->m_nID) //根據標識判斷,工具欄中,菜單欄中的剪切都被禁用
if(0== pCmdUI->m_nIndex) //根據索引判斷,工具欄中的剪切不被禁用,兩者索引不同!
pCmdUI->Enable(FALSE);
}
//如果要在程序中設置某個菜單項的狀態,首先通過ClassWizard爲這個菜單項添加ON_UPDATE_COMMAND_UI消息響應函數,然後再這個
//函數中進行狀態的設置即可!
void CMainFrame::OnShow()
{
//TODO: Add your command handler code here
MessageBox("Mainshow");
}
//動態菜單操作
//1.添加菜單項目
/*CMenumenu;
menu.CreateMenu();//創建一個菜單,然後將其與一個CMenu對象相關聯起來。
GetMenu()->AppendMenu(MF_POPUP,(UINT)menu.m_hMenu,"Test"); //添加菜單項
menu.Detach();//將菜單句柄與菜單對象之間的關聯斷開*/
//2.插入菜單項目
/*CMenumenu;
menu.CreateMenu();//創建一個菜單,然後將其與一個CMenu對象相關聯起來。
GetMenu()->InsertMenu(2,MF_POPUP|MF_BYPOSITION, (UINT)menu.m_hMenu,"Test");
menu.AppendMenu(MF_STRING,IDM_HELLO,"Hello");
menu.AppendMenu(MF_STRING,112,"Bye");
menu.AppendMenu(MF_STRING,113,"Mybole");
menu.Detach();
GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,114,"Welcome");
GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_STRING| MF_BYCOMMAND,115,"VC編程");
//3.刪除菜單
GetMenu()->DeleteMenu(1,MF_BYPOSITION);
GetMenu()->GetSubMenu(0)->DeleteMenu(2,MF_BYPOSITION);*/
//4.動態添加的菜單項的命令響應
void CMainFrame::OnHello()
{
MessageBox("Hello");
}
ON_COMMAND(IDM_HELLO,OnHello)
afx_msg void OnHello();
//5.電話本示例程序
void CMenu2View::OnChar(UINT nChar, UINTnRepCnt, UINT nFlags)
{
CClientDCdc(this);
if(0x0d== nChar)
{
if(0== ++m_nIndex)
{
m_menu.CreatePopupMenu();
GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)m_menu.m_hMenu,"phoneBook");//菜單是框架類窗口的,要用GetParent()
//取到框架窗口的指針
GetParent()->DrawMenuBar();//取得框架窗口的指針,然後重繪菜單欄,纔會在按下回車鍵後顯示先添加的菜單!
//在CMainFrame中不需要這樣做,是因爲代碼是在OnCreate中添加的,窗口還未創建完成
//而此時窗口已經創建完成
}
m_menu.AppendMenu(MF_STRING,IDM_PHONE1+ m_nIndex,m_strLine.Left(m_strLine.Find(' ')));//取得輸入的內容空格以前的內容,添加到菜單項中
m_strArray.Add(m_strLine);//m_strArray是定義的一個CStringArray的集合類
//MFC爲我們提供了一些非常有用的集合類,這些集合類類似於數組的功能,但他們可以很方便的動態增加和刪除元素。
m_strLine.Empty();//在按下回車鍵後,清空字符串的內容,再次輸入時顯示的就是新輸入的,不會在先前的後面輸出了
Invalidate();//讓窗口的整個客戶區無效,這樣,當下一條WM_PAINT消息發生時,窗口就會被更新。不然再次輸入的內容
//會再先前輸入的內容上面顯示。默認參數是TRUE,在窗口重繪時就會把窗口的背景擦除掉。爲FALSE時保留窗口的背景
}
else
{
m_strLine+= nChar;
dc.TextOut(0,0,m_strLine);
}
CView::OnChar(nChar,nRepCnt, nFlags);
}
void CMenu2View::OnPhone1()
{
//TODO: Add your command handler code here
CClientDCdc(this);
dc.TextOut(0,0,m_strArray.GetAt(0));
}
void CMenu2View::OnPhone2()
{
//TODO: Add your command handler code here
CClientDCdc(this);
dc.TextOut(0,0,m_strArray.GetAt(1));
}
void CMenu2View::OnPhone3()
{
//TODO: Add your command handler code here
CClientDCdc(this);
dc.TextOut(0,0,m_strArray.GetAt(2));
}
void CMenu2View::OnPhone4()
{
//TODO: Add your command handler code here
CClientDCdc(this);
dc.TextOut(0,0,m_strArray.GetAt(3));
}
ON_COMMAND(IDM_PHONE1,OnPhone1) //這些代碼要放到註釋宏外面,如果放在裏面,在ClassWizard對話框中,在Message Maps選項卡下
ON_COMMAND(IDM_PHONE2,OnPhone2) //的Member functions列表中就會列出這些函數,放在外面就不會列出來。當ClassWizard發現
ON_COMMAND(IDM_PHONE3,OnPhone3) //菜單項已經被刪除了的時候,它就會把已爲該菜單項添加的消息映射宏也刪除了,這樣,消息映射宏
ON_COMMAND(IDM_PHONE4,OnPhone4) //的三個環節就斷了一環,程序就會出錯。
afx_msgvoid OnPhone1(); //放在兩個註釋宏之間也沒有錯
afx_msgvoid OnPhone2(); //但爲了區分這是自己手動添加的,可以把它們拿出來放在兩個AFX_MSG註釋宏之後。
afx_msgvoid OnPhone3();
afx_msgvoid OnPhone4();