在我們開發桌面軟體的時候,我們經常會遇到這樣一個場景:我們同一個軟體,要給不用的使用者群體使用,功能上有些許差别,比如說Visual Studio就有免費社群版,專業版和企業版。
面對不同的使用者,我們想要提供的服務是不同的,免費版的軟體隻開放部分功能,登入的使用者是學生或者是教師,提供的服務也是不同的,這時,我們就希望使用者登入之後,更具使用者類型來動态加載菜單,僅展示他們需要的功能。
那我們應該怎麼實作呢?
1、建立Doc模闆時傳入公共菜單
首先我們來看一下$ProjectName.cpp檔案:
BOOL CMFCTestApp::InitInstance()
{
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMFCTestDoc),
RUNTIME_CLASS(CMainFrame), // 主 SDI 架構視窗
RUNTIME_CLASS(CMFCTestView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// 分析标準 shell 指令、DDE、打開檔案操作的指令行
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// 排程在指令行中指定的指令。 如果
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 啟動應用程式,則傳回 FALSE。
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 唯一的一個視窗已初始化,是以顯示它并對其進行更新
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
我省略掉了前面的OLE初始化等部分,主要來看一下我們關心的部分。
CSingleDocTemplate是Doc模闆,構造函數的參數分别是資源ID(可以是菜單,工具欄,狀态欄等),文檔類,架構類,視類。
ProcessShellCommand(cmdInfo):這句代碼根據上面的模闆,先後建立了文檔類,架構類和視類。然後就是顯示視窗。
在建立Doc模闆時,我們可以在資源視圖中建立一個公共的菜單傳入,提供注冊,登入等功能,在登入之後提供新的菜單。
2、在視類初始化的時候,更新菜單
在資源檔案中為建立的菜單添加資源ID
Resource.h
#define ID_MENU_TEST0 400
#define ID_MENU_TEST1 401
#define ID_MENU_TEST2 402
在初始化視類的時候,我們可以建立一個全新的菜單,如下:
void CMFCTestView::OnInitialUpdate()
{
CMenu myMenu;
myMenu.CreateMenu(); // 建立普通菜單
myMenu.AppendMenu(MF_STRING, ID_MENU_TEST0, _T(“Test0”)); // 在菜單後追加菜單項
myMenu.AppendMenu(MF_STRING, ID_MENU_TEST2, _T(“Test2”));
myMenu.InsertMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_TEST1, _T(“Test1”)); // 在指定位置插入菜單項,MF_BYPOSITION不能少
AfxGetMainWnd()->SetMenu(&myMenu); // 設定目前菜單
m_hMenuDefault = m_NewMenu.m_hMenu; // 設定預設菜單那
myMenu.Detach();
AfxGetMainWnd()->DrawMenuBar(); // 重繪菜單
}
AppendMenu的第一個參數有以下值(具體請看MSDN文檔):
- MF_CHECKED 充當 MF_UNCHECKED 的切換, 以将預設複選标記置于該項旁邊。 當應用程式提供了檢查标記位圖時, 将顯示 “選中标記” 位圖。
- MF_UNCHECKED 充當 MF_CHECKED 的切換, 以删除項旁邊的複選标記。 當應用程式提供了檢查标記位圖時, 将顯示 “勾号 off” 位圖。
- MF_DISABLED 禁用菜單項, 使其不能被選中但不會使其變暗。
- MF_ENABLED 啟用菜單項, 以便可以選擇它, 并将其還原為灰顯狀态。
- MF_GRAYED 禁用菜單項, 使其不能被選中并使其變暗。
- MF_MENUBARBREAK 将項放置在靜态菜單或彈出菜單的新列中的新行上。 新的彈出菜單列将通過垂直分隔線與舊列分隔開。
- MF_MENUBREAK 将項放置在靜态菜單或彈出菜單的新列中的新行上。 不在列之間放置分隔線。
- MF_OWNERDRAW 指定項是所有者描述項。 當首次顯示菜單時, 擁有菜單的視窗将收到
-
WM_MEASUREITEM 消息, 該消息将檢索菜單項的高度和寬度。 WM_DRAWITEM
消息是指每當所有者必須更新菜單項的視覺外觀時發送的消息。 此選項對于頂級菜單項無效。
-
MF_POPUP 指定菜單項具有與之關聯的彈出菜單。 ID 參數指定要與項關聯的彈出菜單的句柄。
這用于向彈出菜單項添加頂級彈出菜單或層次結構彈出菜單的菜單項。
- MF_SEPARATOR 繪制水準分隔線。 隻能在彈出菜單中使用。 此行不能為灰顯、禁用或突出顯示。 其他參數将被忽略。
- MF_STRING 指定菜單項是一個字元串。
我們也可以在原來菜單的基礎上加以修改,增加我們想要的功能,删除不需要的。實作如下:
void CMFCTestView::OnInitialUpdate()
{
CView::OnInitialUpdate();
CMenu *mainMenu = AfxGetMainWnd()->GetMenu(); // 擷取目前菜單
CMenu *drawingMenu = NULL;
int menuCount = mainMenu->GetMenuItemCount(); // 擷取菜單項數
for (int i = 0; i < menuCount; i++)
{
CString menuName;
if (mainMenu->GetMenuString(i, menuName, MF_BYPOSITION)
&& menuName == "檔案(&F)") // 找到名為"檔案(&F)"的菜單項
{
drawingMenu = mainMenu->GetSubMenu(i);
break;
}
}
CMenu myMenu;
myMenu.CreatePopupMenu(); //建立彈出菜單,點選彈出子菜單
myMenu.AppendMenu(MF_STRING, ID_MENU_TEST0, _T("Test0"));
myMenu.AppendMenu(MF_STRING, ID_MENU_TEST2, _T("Test2"));
myMenu.InsertMenu(1, MF_BYPOSITION | MF_STRING, ID_MENU_TEST1, _T("Test1"));
// 将建立的菜單添加到檔案菜單最後,添加子菜單不需要ID,但是要傳入子菜單的句柄
drawingMenu->AppendMenu(MF_POPUP | MF_STRING, (UINT_PTR)myMenu.m_hMenu, _T("Test"));
myMenu.Detach();
AfxGetMainWnd()->DrawMenuBar();
}
3、添加菜單的處理函數
添加完菜單後,如果沒有添加指令處理函數的話,我們的菜單會是灰色的,無法選中,是以接下來我們要實作菜單的處理函數,實作如下:
// xxx.h
// 在頭檔案中聲明響應函數
protected:
afx_msg void OnMenuTest();
DECLARE_MESSAGE_MAP()
// xxx.cpp
// 在cpp檔案中實作函數,并綁定相關聯的菜單ID
void CMFCTestView::OnMenuTest()
{
AfxMessageBox(_T("MenuTest!"));
// TODO:添加指令處理代碼
}
BEGIN_MESSAGE_MAP(CMFCTestView, CView)
ON_COMMAND(ID_MENU_TEST0, OnMenuTest) // 綁定ID和處理函數,注意,這裡不要分号
END_MESSAGE_MAP()
這樣,我們就可以修改菜單,添加我們需要的功能了。
本文僅針對單文檔MFC應用程式,後續會再寫一篇關于多文檔的動态菜單實作的文章,敬請期待。
如果覺得對您有幫助的話,請掃一下這個二維碼,和小小僧一起成長吧!
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZwpmL4MTNwMjNyEjM3ITMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
版權聲明:本文為CSDN部落客「weixin_41930966」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/weixin_41930966/article/details/103283881