基于单文档的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();即可
原型BOOL SetMenu(HWND hWnd,HMENU hMenu);
功能:该函数分配一个新菜单到指定窗口
参数:
hWnd:菜单被分配到其中的窗口的句柄。
HMenu:新菜单的句柄。如果菜单参数为NULL,则窗口的当前菜单被删除。 函数SetMenu替换原来的菜单(如果存在),但并不将其销毁。应用程序必须调用函数DestroyMenu来销毁菜单。
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
//在客户区点击鼠标左键时,弹出子菜单项
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个或者其他子菜单项更新状态
标题是属于框架类的,不属于视图,,框架包含菜单栏,客户区等。视图只要客户区啊。。。
hICon[0] = AfxGetApp()->LoadIcon(IDI_ICON1);
hICon[1] = AfxGetApp()->LoadIcon(IDI_ICON2);
hICon[2] = AfxGetApp()->LoadIcon(IDI_ICON3);
hICon[3] = AfxGetApp()->LoadIcon(IDI_ICON4);
if(12 == nIDEvent)
{
static int i = 0;
SetClassLong(m_hWnd,GCL_HICON,(LONG)hICon[i]);
i++;
if(4 == i)
{
i = 0;
}
}
功能:设置或者修改窗口类的某些参数
原型:
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 :替换与窗口类有关的窗口过程的地址。
功能:获取现有类型
原型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