WTL 工具栏下拉扩展






3.67/5 (3投票s)
2000年4月28日

159062

1976
一篇关于使用 Window Template Library 扩展工具栏控件的文章。
引言
我需要一个带有下拉箭头的工具栏,以便我可以在上面放置一些弹出菜单。 最初,我尝试在父窗口中处理通知消息。 这变得非常混乱,而且看起来很糟糕。 因此,我决定创建自己的自定义工具栏控件。 这个过程很简单,所以我直接进入代码。
工作原理
1. 我们需要从父窗口检索通知消息。 现在,我们不想简单地反射所有通知消息,因为我们不想处理所有这些消息。 因此,我们创建一个包含的窗口,通过它可以选择性地选择要处理哪些通知消息。
CContainedWindow m_wndParent; //... CToolBarCtrlExImpl() : m_wndParent(this, 1), m_pDropDownButtons(NULL), m_bImagesVisible(false), m_bAnimate(false), m_clrMask(RGB(192, 192, 192)) { //... } //... LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { //... // Subclass parent window CWindow wndParent = GetParent(); CWindow wndTopLevelParent = wndParent.GetTopLevelParent(); m_wndParent.SubclassWindow(wndTopLevelParent); //... }
2. 我们现在已经获得了父窗口的副本,并且正在接收它的所有消息。 接下来,我们需要在消息映射中定义要处理哪些消息。
BEGIN_MSG_MAP(CToolBarCtrlExImpl) //... ALT_MSG_MAP(1) // Parent window messages NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown) NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange) END_MSG_MAP()
请注意,我们正在使用 ALT_MSG_MAP(1)
。 ATL 支持多个消息映射,因此所有属于父窗口的消息现在都通过这里传递。 顺便说一下,父窗口仍然接收所有这些消息,我们只是偷窥一下它们并使用我们需要的消息。
以下代码是工具栏类中的当前消息处理程序
LRESULT OnParentDropDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { LPNMTOOLBAR lpnmtb = (LPNMTOOLBAR)pnmh; // Check if this is from us if (pnmh->hwndFrom != m_hWnd) { bHandled = FALSE; return TBDDRET_NODEFAULT; } _DropDownButton* pb = FindDropDownButton(lpnmtb->iItem); RECT rc; GetRect(pb->uIdButton, &rc); ClientToScreen(&rc); if (pb && pb->uIdMenu) if (DoDropDownMenu(pb->uIdMenu, &rc)) <- See History for comments return TBDDRET_DEFAULT; return TBDDRET_NODEFAULT; } // Do not hot track if application in background LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) { LPNMTBHOTITEM lpnmhi = (LPNMTBHOTITEM)pnmh; // Check if this is from us if (pnmh->hwndFrom != m_hWnd) { bHandled = FALSE; return 0; } DWORD dwProcessID; ::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID); if ((!m_wndParent.IsWindowEnabled() || ::GetCurrentProcessId() != dwProcessID)) return 1; else { bHandled = FALSE; return 0; } }
更新
我刚刚完成向菜单添加位图,以便通常会显示位图的所有菜单项都会显示。
如何使用
在 MainFrm.h 中声明一个 CToolBarCtrlEx,并在 OnCreate 处理程序中像下面的示例一样初始化它。
class CMainFrame : ... { //... CToolBarCtrlEx m_wndToolBar; //... LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { //... // HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE); HWND hWndToolBar = m_wndToolBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_TOOLBAR_PANE_STYLE); m_wndToolBar.LoadToolBar(IDR_MAINFRAME); // Load the toolbar m_wndToolBar.LoadMenuImages(IDR_MAINFRAME); // Load all the menu images were going to need m_wndToolBar.AddDropDownButton(ID_FILE_NEW, IDR_MAINFRAME); // Add some drop-down buttons m_wndToolBar.AddDropDownButton(ID_FILE_OPEN, IDR_POPUP_OPEN); m_wndToolBar.AddDropDownButton(ID_EDIT_PASTE, IDR_POPUP_PASTE); //... } //... };
感谢 Paul DiLascia 提供的将下拉菜单添加到工具栏按钮的代码。(MSJ - 1997)
就这样!
历史
版本 1.1
- 修改了下拉方法,并使其成为一个虚函数,以便可以覆盖它以进行自定义处理。
- 向菜单项添加了位图。
版本 1.0
- 向下拉按钮添加了下拉菜单。