00. 目录

 

 

01. 案例概述

本实例是对工具栏功能的扩充,可以将工具栏上按钮的并列项以菜单的形式显示,方便用户操作。运行程序,单击工具栏按钮旁边的下三角按钮,将弹出一个下拉菜单,如下图所示。
【MFC】带下拉菜单的工具栏_下拉菜单

02. 开发环境

系统环境:Windows 10

开发环境:Visual Studio 2019

03. 关键技术

下三角按钮是通过CToolBar类的SetButtonStyle方法和CToolBarCtrl类的SetExtendedStyle方法实现的。

SetButtonStyle方法主要用来设置工具栏按钮的风格,语法如下:

void SetButtonStyle( int nIndex, UINT nStyle );

参数说明
    nIndex:按钮的索引。
    nStyle:按钮的风格。可以有以下取值。
    TBBS_BUTTON:标准按钮。
    TBBS_SEPARATOR:分隔线。
    TBBS_CHECKBOX:复选风格。
    TBBS_GROUP:按钮组。
    TBBS_CHECKGROUP:复选按钮组。

SetExtendedStyle方法用于设置工具栏控件的扩展风格,语法如下:

DWORD SetExtendedStyle( DWORD dwExStyle ) const;
参数说明
	dwExStyle:系统定义的工具栏控件风格,取值TBSTYLE_EX_DRAWDDARROWS,可以实现下三角按钮功能。

04. 程序设计

4.1 在OnCreate函数中针对创建的Toolbar获取到对应的按钮属性,并设置为具有下拉风格

	//设置工具栏有下拉按钮
	m_wndToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
	//获得添加下拉按钮的工具栏打开按钮风格
	DWORD dwStyle = m_wndToolBar.GetButtonStyle(m_wndToolBar.CommandToIndex(ID_FILE_OPEN));
	//添加下拉按钮风格
	dwStyle |= TBSTYLE_DROPDOWN;
	m_wndToolBar.SetButtonStyle(m_wndToolBar.CommandToIndex(ID_FILE_OPEN), dwStyle);

4.2 创建你点击Toolbar上对应的按钮后需要下拉的菜单栏,插入新的Resouse:Menu,在这里我新建的Menu它的ID是ID_DRAW_LINE

4.3 在CMainFrame类的消息映射中(即MainFrm.cpp )加入下拉箭头的ID_DRAW_LINE消息映射

此消息映射需要手动添加,添加步骤

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_WM_CREATE()
	ON_NOTIFY(TBN_DROPDOWN, AFX_IDW_TOOLBAR, OnToolbarDropDown)//此行即为新增的ON_NOTIFY消息映射
	ON_COMMAND(ID_TEST_32771, &CMainFrame::OnTest32771)
	ON_COMMAND(ID_TEST_32772, &CMainFrame::OnTest32772)
END_MESSAGE_MAP()

4.4 在MainFrame.h头文件中加入消息处理函数的声明:

afx_msg void OnToolbarDropDown(NMHDR* pnmhdr, LRESULT* plRes);

4.5 在MainFrame.cpp中实现消息处理函数和添加响应处理函数

// CMainFrame 消息处理程序
void CMainFrame::OnToolbarDropDown(NMHDR* pnmhdr, LRESULT* plRes)
{

	LPNMTOOLBAR pnmh = reinterpret_cast<LPNMTOOLBAR>(pnmhdr);
	CWnd* pWnd;

	switch (pnmh->iItem)
	{
	case ID_FILE_OPEN:
		pWnd = &m_wndToolBar;
		break;
	default:
		//此处必须写return 否则在vs2019中会报错
		return;
	}

	//pWnd = &m_wndToolBar;

	CMenu menu;
	//加载菜单资源
	menu.LoadMenuW(ID_DRAW_LINE);
	//获得子菜单
	CMenu* pPopub = menu.GetSubMenu(0);
	ASSERT(pPopub);

	CRect rect;
	//获得区域
	pWnd->SendMessage(TB_GETRECT, pnmh->iItem, (LPARAM)&rect);
	pWnd->ClientToScreen(&rect);
	pPopub->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL, 
                           rect.left, rect.bottom, this, &rect);
}


void CMainFrame::OnTest32771()
{
	// TODO: 在此添加命令处理程序代码
	MessageBox(TEXT("Release"));
}


void CMainFrame::OnTest32772()
{
	// TODO: 在此添加命令处理程序代码
	MessageBox(TEXT("Debug"));
}

05. 秘笈心法