精通 VC++ 实效编程280例 - 02 菜单和光标
菜单和关闭时重要的 Windows 资源之一。SDK 中,用 HCURSOR 和 HMENU 分别表示菜单和光标的句柄。MFC 中,CMenu 类封装了菜单的功能。
23 动态添加和删除菜单项
添加菜单项可以调用 CMenu::AppendMenu 或 CMenu::InserMenu 函数,删除菜单项可以调用 CMenu::RemoveMenu 或 CMenu::DeleteMenu 函数,最后调用 CWnd::DrawMenuBar 函数重画菜单。
- CMenu::AppendMenu:在菜单末端添加菜单项。
- CMenu::InserMenu:在菜单指定位置添加菜单项。
- CMenu::RemoveMenu:移动菜单项,如果菜单项与弹出菜单相关联,将不将销毁弹出菜单的句柄,因此菜单可重用。
- CMenu::DeleteMenu:删除菜单项,如果菜单项与弹出菜单相关联,将销毁弹出菜单的句柄,并释放其占用的内存。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
#define ID_TEST_MENU 10000 void CMainFrame::OnAppendMenu() { //获得主菜单 CMenu* pMenu = GetMenu(); //获得子菜单 CMenu* pSubMenu = pMenu->GetSubMenu(4); if (pSubMenu->GetMenuItemCount() == 4) { //在菜单末端添加菜单项 pSubMenu->AppendMenu(MF_STRING,ID_TEST_MENU,_T( "New Menu" )); //重画菜单 DrawMenuBar(); } } void CMainFrame::OnInsertMenu() { //获得主菜单 CMenu* pMenu = GetMenu(); //获得子菜单 CMenu* pSubMenu = pMenu->GetSubMenu(4); if (pSubMenu->GetMenuItemCount() == 4) { //在菜单指定位置添加菜单项 pSubMenu->InsertMenu(4,MF_BYPOSITION,ID_TEST_MENU,_T( "New Menu" )); //重画菜单 DrawMenuBar(); } } void CMainFrame::OnRemoveMenu() { //获得主菜单 CMenu* pMenu = GetMenu(); //获得子菜单 CMenu* pSubMenu = pMenu->GetSubMenu(4); if (pSubMenu->GetMenuItemCount() == 5) { //删除菜单项 pSubMenu->RemoveMenu(4,MF_BYPOSITION); //重画菜单 DrawMenuBar(); } } void CMainFrame::OnDeleteMenu() { //获得主菜单 CMenu* pMenu = GetMenu(); //获得子菜单 CMenu* pSubMenu = pMenu->GetSubMenu(4); if (pSubMenu->GetMenuItemCount() == 5) { //删除菜单项 pSubMenu->DeleteMenu(4,MF_BYPOSITION); //重画菜单 DrawMenuBar(); } } void CMainFrame::OnTestMenu() { AfxMessageBox(_T( "测试菜单项命令" )); } |
24 在系统菜单中添加和删除菜单项
在系统菜单中添加和删除菜单项,首先调用 CWnd::GetSystemMenu 函数获得系统菜单的指针,然后调用 CMenu::AppendMenu 或 CMenu::InsertMenu,CMenu::RemoveMenu 或 CMenu::DeleteMenu 函数添加和删除菜单项,最后调用 CWnd::DrawMenuBar 函数重画菜单。对于添加的菜单项,可以在 CWnd::OnSysCommand 重载函数中处理菜单命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
//在resource.h文件中添加宏定义 #define ID_TEST_MENU 10000 BOOL CDemoDlg::OnInitDialog() { CDialog::OnInitDialog(); //... //获得系统菜单 CMenu* pMenu = GetSystemMenu(FALSE); //删除系统菜单项 pMenu->RemoveMenu(SC_MOVE,MF_STRING); //添加菜单项 pMenu->InsertMenu(0,MF_BYPOSITION,ID_TEST_MENU,_T( "New Menu" )); //重画菜单 DrawMenuBar(); return TRUE; } void CDemoDlg::OnSysCommand( UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else if (nID == ID_TEST_MENU) { AfxMessageBox(_T( "测试菜单项命令" )); } else { CDialog::OnSysCommand(nID, lParam); } } |
25 禁用关闭按钮
禁用关闭按钮可以调用 CMenu::EnableMenuItem 函数。
1
2
3
4
5
6
7
8
9
10
|
BOOL CDemoDlg::OnInitDialog() { CDialog::OnInitDialog(); //... //获得系统菜单 CMenu* pMenu = GetSystemMenu(FALSE); //禁用关闭按钮 pMenu->EnableMenuItem(SC_CLOSE,MF_BYCOMMAND | MF_GRAYED); return TRUE; } |
26 启用和禁用菜单项
可以在类的 UPDATE_COMMAND_UI 消息处理函数中调用 CCmdUI::Enable 函数,启用和禁用菜单项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//在CMainFrame类中添加成员变量 public : BOOL m_bEnable1; BOOL m_bEnable2; //在CMainFrame类的构造函数中初始化成员变量 CMainFrame::CMainFrame() { m_bEnable1 = TRUE; m_bEnable2 = FALSE; } //在CMainFrame类中为菜单项添加命令处理函数 void CMainFrame::OnTestMenu1() { m_bEnable1 = FALSE; m_bEnable2 = TRUE; } void CMainFrame::OnUpdateTestMenu1(CCmdUI* pCmdUI) { //启动或禁用菜单1 pCmdUI->Enable(m_bEnable1); } void CMainFrame::OnTestMenu2() { m_bEnable1 = TRUE; m_bEnable2 = FALSE; } void CMainFrame::OnUpdateTestMenu2(CCmdUI* pCmdUI) { //启动或禁用菜单2 pCmdUI->Enable(m_bEnable2); } |
27 设置菜单项的检查状态
可以在类的 UPDATE_COMMAND_UI 消息处理函数中调用 CCmdUI::SetCheck 函数设置菜单项的检查状态(选中/不选中状态)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//在CMainFrame类中添加成员变量 public : int m_nCheck; //在CMainFrame类的构造函数中初始化成员变量 CMainFrame::CMainFrame() { m_nCheck = 0; } //在CMainFrame类中为菜单项添加命令处理函数 void CMainFrame::OnTestMenu() { if (m_nCheck == 0) { m_nCheck = 1; } else { m_nCheck = 0; } } void CMainFrame::OnUpdateTestMenu(CCmdUI* pCmdUI) { //设置菜单项检查状态 pCmdUI->SetCheck(m_nCheck); } |
28 快捷菜单
实现快捷菜单可以在 CWnd::OnContextMenu 重载函数中调用 CMenu::TrackPopupMenu 函数。
在资源中添加1个菜单资源,ID 为 IDR_MENU。在菜单资源中添加1个子菜单,并添加菜单项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//在CDemoView类中重载CWnd::OnContextMenu函数 void CDemoView::OnContextMenu(CWnd* pWnd, CPoint point) { CMenu menu; //加载菜单 if (!menu.LoadMenu(IDR_MENU)) { return ; } //获得子菜单 CMenu* pPopupMenu = menu.GetSubMenu(0); //弹出菜单 pPopupMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,point.x,point.y,pWnd); } void CDemoView::OnTestMenu1() { AfxMessageBox(_T( "快捷菜单项1命令" )); } void CDemoView::OnTestMenu2() { AfxMessageBox(_T( "快捷菜单项2命令" )); } |
29 获取光标的坐标
可以在 WM_MOUSEMOVE 消息处理函数中获得光标的位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
//在CDemoView类中添加成员变量 public : CPoint m_Point; //在类中添加WM_MOUSEMOVE消息处理函数 void CDemoView::OnMouseMove( UINT nFlags, CPoint point) { //保存光标坐标 m_Point = point; //刷新客户区 Invalidate(); CView::OnMouseMove(nFlags, point); } //在类中重载CView::OnDraw函数 void CDemoView::OnDraw(CDC* pDC) { //获得客户区坐标 CRect rect; GetClientRect(rect); //绘制十字光标 pDC->MoveTo(0,m_Point.y); pDC->LineTo(rect.Width(),m_Point.y); pDC->MoveTo(m_Point.x,0); pDC->LineTo(m_Point.x,rect.Height()); //输出光标坐标 CString strText = _T( "" ); strText.Format(_T( "%d,%d" ),m_Point.x,m_Point.y); pDC->SetBkMode(TRANSPARENT); pDC->SetTextAlign(TA_RIGHT | TA_BOTTOM); pDC->TextOut(m_Point.x,m_Point.y,strText); } |
30 限制光标的移动范围
限制光标的范围可以调用 SDK 的 ClipCursor 函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
//在CDemoView类中重载CView::OnDraw函数 void CDemoView::OnDraw(CDC* pDC) { //获得客户区坐标 CRect rect; GetClientRect(rect); rect.left = rect.left + rect.Width() / 4; rect.right = rect.right - rect.Width() / 4; rect.top = rect.top + rect.Height() / 4; rect.bottom = rect.bottom -rect.Height() / 4; //绘制光标移动范围 pDC->Rectangle(rect); } //在CDemoView类中分别添加WM_LBUTTONDOWN和WM_LBUTTONUP消息处理函数 void CDemoView::OnLButtonDown( UINT nFlags, CPoint point) { //获得客户区坐标 CRect rect; GetClientRect(rect); rect.left = rect.left + rect.Width() / 4; rect.right = rect.right - rect.Width() / 4; rect.top = rect.top + rect.Height() / 4; rect.bottom = rect.bottom - rect.Height() /4; //映射屏幕坐标 ClientToScreen(rect); //限制光标移动范围 ClipCursor(&rect); CView::OnLButtonDown(nFlags, point); } void CDemoView::OnLButtonUp( UINT nFlags, CPoint point) { //光标自由移动 ClipCursor(NULL); CView::OnLButtonUp(nFlags, point); } |
31 自定义光标
使用自定义光标,首先调用 CWinApp::LoadCursor函数加载光标,然后调用SDK的SetCursor函数设置光标。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//创建1个单文档的应用程序,并添加2个光标资源,在CDemoView类中添加成员变量 public : HCURSOR m_hCursor; //在CDemoView类中重载CView::OnInitialUpdate函数 void CDemo2View::OnInitialUpdate() { CView::OnInitialUpdate(); //加载光标 m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1); } //在CDemoView类中添加WM_SETCURSOR消息处理函数 BOOL CDemo2View::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { //设置光标 ::SetCursor(m_hCursor); return TRUE; } //在CDemoView类中分别添加WM_LBUTTONDOWN和WM_LBUTTONUP消息处理函数 void CDemo2View::OnLButtonDown( UINT nFlags, CPoint point) { //加载光标 m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR2); //设置光标 ::SetCursor(m_hCursor); CView::OnLButtonDown(nFlags, point); } void CDemo2View::OnLButtonUp( UINT nFlags, CPoint point) { //加载光标 m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR1); //设置光标 ::SetCursor(m_hCursor); CView::OnLButtonUp(nFlags, point); } |
32 等待光标
启动等待光标可以调用 CCmdTarget::BeginWaitCursor函数,结束等待光标可以调用CCmdTarget::EndWaitCursor函数。
1
2
3
4
5
6
7
8
9
10
|
void CDemo2View::OnLButtonUp( UINT nFlags, CPoint point) { //启动等待光标 BeginWaitCursor(); //休眠 Sleep(5000); //结束等待光标 EndWaitCursor(); CView::OnLButtonDown(nFlags,point); } |
转自:http://www.cnblogs.com/iwanc/archive/2013/06/09/2987866.html
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。