CGSToolBar






3.86/5 (8投票s)
CToolBar 类的灵活扩展
引言
在我的当前项目中,我发现自己拥有大量的工具栏。这是一个绘画程序,因此将各种工具栏放置在图像的部分区域上,并且一半的空间只是浪费的空间(即标题栏),这开始变得非常痛苦。我决定尝试编写一个从 CToolBar
派生的类,该类被欺骗为认为它已停靠,但实际上并非如此,因此它绘制时带有夹具且没有标题栏。很简单,对吧?
好吧,最后,我在这里提出了一个问题,并从 Masoud 那里得到了答案,他也试图做同样的事情。他找到了答案,并且在此过程中,我们互相交流了想法,最终得到了一个有用的工具栏类,我们认为值得分享。请将所有赞美之词都献给我,任何错误都是他的错(只是开玩笑,Masoud ;0)
要使用 CGSToolBar
,只需在您的 CMainFrame
标题中包含头文件,然后将工具栏资源替换为 CGSToolBar。对于自动菜单,您还需要创建三个资源 ID,即 ID_MENU_GRADIENT
、ID_MENU_CAPTION
和 ID_MENU_BUTTONS
。稍后会详细介绍这些。
CGSToolBar
的头文件列出了以下附加函数
// Function to dock bars next to one another (used typically on startup) void DockBarNextTo(CControlBar* pDockedBar, UINT nDockBarID = 0); // Self Explanatory bool IsBarVisible() { return ((this->GetStyle() & WS_VISIBLE) !=0); }; // Three functions to change the contents of a button // First one takes a pointer to a bitmap and a 0 based position void OnChangeButton(CBitmap * pButton, int Position); // Second used a resource ID, position, and transparent colour. // Transparency does not work with gradient, this is the fault of the gradient code void OnChangeButton(int BitmapID, int Position,COLORREF Transp = RGB(255,0,255)); // Last one changes to a solid colour ( remember this was for a paint program ;0) void OnChangeButton(COLORREF colour, int Position); // Sets a button to have a drop down arrow next to it. // See code for further instructions on how to use this, or the MSDN void SetDropdown(int Position); // Push buttn mode means the last button pushed stays 'down', useful for example // if toolbar selects different 'modes' // First function sets global behaviour void SetPushButton (bool push); // Second allows you to specific individual buttons to group together this way. void SetPushButton (bool push, int nPos); // The core function - this turns the caption bar off and on // When it is off, the floated toolbar has a gripper and resizes slightly to allow dragging void SetShowCaption (bool caption); // This just calls SetWindowText, but I put it in just in case anyone didn't realise that is how to do it void SetCaption (CString caption); // Sets the colours for the gradient void SetBackground(COLORREF col1, COLORREF col2) { m_RGB1 = col1; m_RGB2 = col2; }; // The gradient is drawn in OnEraseBackground - a solid colour or bitmap could just as easily be used. void SetUseGradient(bool grad) { m_bUseGradient = grad; }; // This allows you to pass in a menu to be shown as a context menu void SetMenu(int ID) { m_iMenuID = ID; }; // These four turn on the extra menu items available, to allow the user to turn on and off pushbuttons, the caption bar and the gradient fill void SetMenuAll(bool menu); void SetMenuPushbutton (bool bPush); void SetMenuCaption (bool bCaption); void SetMenuGradient (bool bGradient); // Fairly obvious stuff bool GetShowCaption() { return m_bShowCaption; }; bool GetUseGradient() { return m_bUseGradient; }; bool GetPushbutton() { return m_bPushButton; };
有几个特别感兴趣的项目。
OnChangeButton
方法使用资源,还可以透明地显示位图。它通过生成 1 位 alpha 掩码来实现,即位图在应该绘制的地方是白色,而在不应该绘制的地方是黑色。在 CodeProject 的相应部分中,有其他更通用的示例说明如何使用此方法进行颜色键控透明度。Windows 有一个 TransparentBlt
函数,但 Windows 95 不支持它,因此最好不要使用它。
SetMenu
允许您传入任何菜单的 ID,它将用作上下文菜单,但是通过使用列出的其他 SetMenu
方法,您还可以使 CGSToolBar
为您的菜单提供这些额外的选项。例如,我传入一个列出我所有工具栏的菜单,因此我获得了 MSDev 类型的行为,即右键单击使我可以打开和关闭工具栏,但在顶部,我可以让用户选择他们是否想要标题栏。
SetDropDown
允许您设置一个按钮,以便在您按下提供的箭头时显示菜单,但需要在 CMainFrame
中完成一些工作才能实现此目的。基本上,您需要在 OnNotify
中捕获 TBN_DROPDOWN
,然后确定按下了哪个工具栏并显示/处理相应的菜单。如果您只有一个工具栏,则可以直接覆盖 OnDropDown
。您可以通过将 TPM_RETURNCMD
传递给 TrackPopupMenu
并获取返回的 DWORD
来获取菜单以将选择值返回给您,然后您可以切换它。这里有其他教程介绍如何执行此操作,并且本文的重点不是重复它们。此行为未在演示项目中显示。
我们必须做的最棘手的事情可能是使工具栏在绘制时的轮廓大小正确。事实证明,尽管 MSDN 对此问题保持沉默,但这是由 CDockContext
类型的工具栏中的一个对象完成的,称为m_pDockContext。它跟踪四个 LPRECT
结构,并且我们在按下鼠标左键时通过触发计时器来更新它们。我们需要在未停靠时和停靠时都更改它,以便它始终以正确的大小显示。当我说总是时,我没有找到一种最初更改此 rect 的方法,因为我无法成功覆盖该类并将 CGSToolBar
中的对象替换为我们自己的对象,并且 RECT
在 BeginDragging
方法中设置。最终结果是,当您单击时会绘制一个不正确的 rect,但当您移动时它是正确的,并且在完成后会捕捉到您正在拖动的轮廓。