zoukankan      html  css  js  c++  java
  • 精通 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:删除菜单项,如果菜单项与弹出菜单相关联,将销毁弹出菜单的句柄,并释放其占用的内存。
    #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 重载函数中处理菜单命令。

    //在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 函数。

    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 函数,启用和禁用菜单项。

    //在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 函数设置菜单项的检查状态(选中/不选中状态)。

    //在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个子菜单,并添加菜单项。

    //在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 消息处理函数中获得光标的位置。

    //在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 函数。

    //在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个光标资源,在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函数。

    void CDemo2View::OnLButtonUp(UINT nFlags, CPoint point) 
    {
    	//启动等待光标
    	BeginWaitCursor();
    	//休眠
    	Sleep(5000);
    	//结束等待光标
    	EndWaitCursor();
    	CView::OnLButtonDown(nFlags,point);
    }
    

      

  • 相关阅读:
    【老孙随笔】关羽和吕蒙——天才的失败
    【老孙随笔】项目经理要向唐骏学习
    WebService里奇怪的参数值偏移现象?
    [原创]让您的服务器不再有被挂马的烦恼文件安全卫士
    C#里也可以用上Eval函数了:)
    使用HTTP_X_FORWARDED_FOR获取客户端IP的严重后果
    支持算术运算、逻辑运算、位运算的表达式求值
    在Lambda表达式中进行递归调用
    认识Lambda表达式
    将你的QQ唠叨或QQ签名数据加入到博客上:)
  • 原文地址:https://www.cnblogs.com/iwanc/p/2987866.html
Copyright © 2011-2022 走看看