基於單文件MFC的選單的操作
基於單文件的MFC標準的程式
選單命令的訊息路由:
由快到慢
檢視 (最快) > 文件 > 框架類 > 應用程式類
如果同一個選單命令 在上面四個中都有處理函式,則只相應 檢視,如果將檢視中處理函式刪掉,則只相應 文件類的,以此類推。
**-
關於選單的幾個操作
在MainFrm.cpp的OnCreate函式下:
思路:獲取主選單–》獲取子選單-》給第3和5個選單項做標記√–》給第5個子選單 設為預設項–》給第5個變灰
【注意】分隔符也佔一個位置啊,列印是第6個,但引數裡面是5哦,從零開始數。
//獲取主選單 CMenu *menu = GetMenu();//獲取主選單, //獲取子選單 CMenu *Filemenu = menu->GetSubMenu(0);//獲取子選單 //標記√ 兩種方式 Filemenu->CheckMenuItem(2,MF_BYPOSITION | MF_CHECKED); Filemenu->CheckMenuItem(ID_FILE_PRINT_SETUP,MF_BYCOMMAND | MF_CHECKED); //設定預設項 一個菜單隻有一個預設項 FALSE為 ID ; true 為位置 //Filemenu->SetDefaultItem(ID_FILE_PRINT,FALSE);//列印(P)... Filemenu->SetDefaultItem(3,true);////列印(P)...注意分隔符也佔一個位置啊 //變灰 CFrameWnd:: m_bAutoMenuEnable = false; //注意變灰這個,需要在建構函式中 新增m_bAutoMenuEnable = false;!!!! Filemenu->EnableMenuItem(5,MF_BYPOSITION | MF_DISABLED); //分隔符設定問題--》》》》》 右擊選單 屬性 separator 改為false即可
載入新選單
**思路:**如果有舊的,可以先移除,載入新選單,設定選單
//移除選單//為NULL時全部移除
SetMenu(NULL);//CMenu::RemoveMenu()必須給指定的刪除哪一個子項
//載入選單
CMenu menuNew;
menuNew.LoadMenu(IDR_NEW_MENU);
SetMenu(&menuNew);
menuNew.Detach();//這個必須要有,沒有程式崩潰
如果只有上面前三行程式則會程式崩潰,因為menuNew是一個區域性變數。
解決辦法:
一: CMenu menuNew; 設定為全域性變數
二: 在上面程式碼中新增 menuNew.Detach();即可
幾個重要函式:
- SetMenu()
原型BOOL SetMenu(HWND hWnd,HMENU hMenu);
功能:該函式分配一個新選單到指定視窗
引數:
hWnd:選單被分配到其中的視窗的控制代碼。
HMenu:新選單的控制代碼。如果選單引數為NULL,則視窗的當前選單被刪除。 函式SetMenu替換原來的選單(如果存在),但並不將其銷燬。應用程式必須呼叫函式DestroyMenu來銷燬選單。
- TrackPopupMenu
功能:彈出子選單
BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd,LPCRECT lpRect = NULL );
引數: x,y是指螢幕左邊。如果是View中新增WM_LBUTTONDOWM 獲得Point是客戶區座標,需要用ClientToScreen(&point)來轉換 - 子選單欄的有兩種訊息
一:ON_UPDATE_COMMAND_UI 處理使用者介面顯示狀態:變灰,√
二:COMMAND :點選按鍵,設定變數m_bIsUpdate來控制上面的情況
訊息:ON_UPDATE_COMMAND_UI 選中子選單-> 右擊 新增事件處理程式–選擇 CMainFrame。這個訊息可以處理當前子選單的狀態,比如何時變灰啊,加√啊,加文字,加單選啊,用其他函式下的變數【標誌位】來控制這個何時需要何種變化狀態。
用這種方式比 在OnCreate中( 先獲得主選單,再獲得子選單,在操作子選單變灰 )這種要方便,因為選單是內部自動更新,會有重繪等操作,會相應這個訊息的。
選單更新機制
ON_UPDATE_COMMAND_UI 這個訊息來,選單有內部自動更新功能,通過標誌位來更新選單。
子選單的介面更新
【重點】用一個標誌變數去控制子選單的更新,在框架類中實現的
//ON_UPDATE_COMMAND_UI 訊息的作用:
//功能:點選B 使A變灰或者不變灰//選單欄是自動內部更新的,重新呼叫繪製選單欄
//選單是內部自動更新
//A的子選單的更新
void CMainFrame::OnUpdateTest(CCmdUI *pCmdUI)
{
// TODO: 在此新增命令更新使用者介面處理程式程式碼
if(true == m_bIsUpdata)
{
pCmdUI->Enable(TRUE);
// pCmdUI->SetCheck();
pCmdUI->SetRadio();
}
else
{
pCmdUI->Enable(FALSE);
pCmdUI->SetCheck(false);
}
}
//m_bIsUpdata 全域性私有變數
//點選B選單項時處理函式 命令處理函式
void CMainFrame::OnTestB()//B的訊息處理函式
{
// TODO: 在此新增命令處理程式程式碼
m_bIsUpdata = !m_bIsUpdata;//控制A中選單更新
}
【關於基於對話方塊的選單欄沒有更新的問題】
參考https://blog.csdn.net/xuanyin235/article/details/80905655
檢視中操作選單:左鍵單擊彈出子選單項
- 在客戶區點選滑鼠左鍵時,彈出子選單視窗
由於客戶區的話,則在檢視視窗新增WM_LBUTTONDOWM訊息。
思路:
【報錯】獲取主選單-> 獲取子選單->操作就可以
【正確】載入選單->獲取子選單-》座標轉換-》彈出子選單
但CMenu *menu = GetMenu();//成功
CMenu *SubMenu = menu->GetSubMenu(0);//不成功
這個獲取就不成功呢,是因為選單是屬於框架類的,如果在檢視中操作時,需要先載入選單項,然後在處理。而且,彈出的子選單項再點選時不會相應像mainfrm.cpp中訊息
//在客戶區點選滑鼠左鍵時,彈出子選單項
void CMy05_MenueView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此新增訊息處理程式程式碼和/或呼叫預設值
//選單是屬於框架類的,如果在檢視中操作時,需要先載入選單項,然後在處理。//而且,彈出的子選單項再點選時不會相應像mainfrm.cpp中訊息
CMenu mee;
mee.LoadMenuW(IDR_NEW_MENU);
CMenu *SubMenu = mee.GetSubMenu(0);
ClientToScreen(&point);
SubMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_LEFTBUTTON,point.x,point.y,this);
CView::OnLButtonDown(nFlags, point);
}
點選選單第2個子選單,使第3個或者其他子選單項更新狀態
載入動態圖示
標題是屬於框架類的,不屬於檢視,,框架包含選單欄,客戶區等。檢視只要客戶區啊。。。
- 新增資源–匯入圖示資源
- 在MainFrame.h中定義圖示的控制代碼,如果多個用陣列:HICON hICon[4];
- 在CMainFrame::CMainFrame()建構函式中 給圖示控制代碼初始化
hICon[0] = AfxGetApp()->LoadIcon(IDI_ICON1);
hICon[1] = AfxGetApp()->LoadIcon(IDI_ICON2);
hICon[2] = AfxGetApp()->LoadIcon(IDI_ICON3);
hICon[3] = AfxGetApp()->LoadIcon(IDI_ICON4);
- 在OnCreate中 開啟定時器 SetTimer(12,500,NULL);
- 在定時器中修改標題: SetClassLong函式非常重要
if(12 == nIDEvent)
{
static int i = 0;
SetClassLong(m_hWnd,GCL_HICON,(LONG)hICon[i]);
i++;
if(4 == i)
{
i = 0;
}
}
函式SetClassLong
功能:設定或者修改視窗類的某些引數
原型:
DWORD SetClassLong(HWND hWnd,int nlndex,LONG dwNewLong)
hWnd:視窗控制代碼及間接給出的視窗所屬的類。
nlndex:指定將被替換的32位值
dwNewLong:指定的替換值。
返回值:
返回值的型別:DWORD
如果要設定WNDCLASSEX結構中的任何值,需要指定下面索引之一:
GCL_CBCLSEXTRA:設定與類相關的尺寸的位元組大小。設定該值不改變己分配的額外位元組數。
GCL_CBWNDEXTRA:設定與類中的每一個視窗相關的尺寸的位元組大小。設定該值不改變已分配額外位元組數。檢視如何進入該記憶體,參看SetWindowLOng。
GCL_HBRBACKGROUND:替換與類有關的背景刷子的控制代碼。
GCL_HCURSOR:替換與類有關的游標的控制代碼。
GCL_HICON:替換與類有關的圖示的控制代碼。
GCL_HMODULE:替換註冊類的模組的控制代碼。
GCL_STYLE:替換視窗類的風格位。
GCL_MENUNAME :替換選單名字串的地址。該字串標識與類有關的選單資源。
GCL_WNDPROC :替換與視窗類有關的視窗過程的地址。
函式 GetClassLong
功能:獲取現有型別
原型DWORD GetClassLong(HWND hWnd,int nlndex);
DWORD SetClassLong 替換指定視窗所屬類的WNDCLASSEX結構,對視窗所屬類的視窗進行修改,
LONG SetWindowLong 該函式改變指定視窗的屬性,對具體的視窗的樣式尺寸等進行修改
區別:一個是操作所屬類,一個操作具體視窗,而且返回值不太一樣
在孫鑫寫的那本書上的例子:
SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd,GWL_STYLE));
【備註】單文件程式中
A 檢視 CView :: CWnd
B 框架 CFrame::CWnd
C 文件 Cdocument :: CCmdTarget
D 應用程式類 CWinApp:: CCmdTarget
AB可以用CWnd::MessagBox CD只能用AfxMessageBox 因為CD不是繼承與CWnd