MFC单文档动态菜单

在我们开发桌面软件的时候,我们经常会遇到这样一个场景:我们同一个软件,要给不用的用户群体使用,功能上有些许差别,比如说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应用程序,后续会再写一篇关于多文档的动态菜单实现的文章,敬请期待。
如果觉得对您有帮助的话,请扫一下这个二维码,和小小僧一起成长吧!

在这里插入图片描述
原文链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值