65.9K
CodeProject 正在变化。 阅读更多。
Home

WTL 工具栏下拉扩展

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (3投票s)

2000年4月28日

viewsIcon

159062

downloadIcon

1976

一篇关于使用 Window Template Library 扩展工具栏控件的文章。

  • 下载演示项目 - 58 Kb
  • 下载源代码文件 - 11 Kb
  • Sample Image

    引言

    我需要一个带有下拉箭头的工具栏,以便我可以在上面放置一些弹出菜单。 最初,我尝试在父窗口中处理通知消息。 这变得非常混乱,而且看起来很糟糕。 因此,我决定创建自己的自定义工具栏控件。 这个过程很简单,所以我直接进入代码。

    工作原理

    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

    • 向下拉按钮添加了下拉菜单。
    © . All rights reserved.