Download source files - 29 Kb
Download demo executable - 11 Kb
Introduction
During my current project, I found myself in possession
of a number of toolbars. It's a paint program, so it started to be quite
painful, having various toolbars over parts of the image, and half of the real
estate is just wasted room (i.e. the caption bar ). I decided to try and
write a class derived from CToolBar
that was tricked into thinking it was docked
when it wasn't, so it drew with a gripper and no caption bar. Simple,
right?
Well, in the end, I posted a question here, and
got an answer from Masoud, who was trying to do the same thing. He found
the answer, and along the way we bounced ideas off each other and ended up with a
useful toolbar class that we thought was worth sharing. Please direct all
compliments to me, any bugs are his fault ( only kidding Masoud ;0)
To use CGSToolBar
, just include the header file in your
CMainFrame
header, and replace toolbar resources with CGSToolBar. For the auto menus, you also need to
create three resource ID's, namely ID_MENU_GRADIENT
, ID_MENU_CAPTION
, and
ID_MENU_BUTTONS
. More on those later.
The header file for CGSToolBar
lists the following extra
functions:
void DockBarNextTo(CControlBar* pDockedBar, UINT nDockBarID = 0);
bool IsBarVisible() { return ((this->GetStyle() & WS_VISIBLE) !=0); };
void OnChangeButton(CBitmap * pButton, int Position);
void OnChangeButton(int BitmapID, int Position,COLORREF Transp = RGB(255,0,255));
void OnChangeButton(COLORREF colour, int Position);
void SetDropdown(int Position);
void SetPushButton (bool push);
void SetPushButton (bool push, int nPos);
void SetShowCaption (bool caption);
void SetCaption (CString caption);
void SetBackground(COLORREF col1, COLORREF col2) { m_RGB1 = col1; m_RGB2 = col2; };
void SetUseGradient(bool grad) { m_bUseGradient = grad; };
void SetMenu(int ID) { m_iMenuID = ID; };
void SetMenuAll(bool menu);
void SetMenuPushbutton (bool bPush);
void SetMenuCaption (bool bCaption); void SetMenuGradient (bool bGradient);
bool GetShowCaption() { return m_bShowCaption; };
bool GetUseGradient() { return m_bUseGradient; };
bool GetPushbutton() { return m_bPushButton; };
There are a few items of particular interest.
The OnChangeButton
method which uses a resource also displays the bitmap
transparently. It does this by generating a 1 bit alpha mask, that is, a
bitmap that is white where it should draw, and black where it should not.
There are other, more generic examples of how to do colour keyed transparency
using this method in the appropriate section of CodeProject. Windows has a
TransparentBlt
function, but it is not supported in Windows 95, so you're better
not to use it.
The SetMenu
allows you to pass in the ID of any menu and it will be used as a
context menu, BUT by using the other SetMenu
methods listed, you can also get
CGSToolBar
to give you these extra options to your menu. For exmaple, I
pass in a menu that lists all my toolbars, so I get MSDev type behaviour where a
right click lets me turn toolbars off and on, but at the top I let my users
choose if they want caption bars or not.
SetDropDown
allows you to set up a button to display a menu when you push the
arrow provided, but there is work to be done in CMainFrame
to make this
happen. Basically you need to catch TBN_DROPDOWN
in OnNotify
, and then
figure out which toolbar was pressed and show/handle the appropriate menu.
If you only have one toolbar you can override OnDropDown
directly. You can
get a menu to return the selection value to you by passing TPM_RETURNCMD
to
TrackPopupMenu
and grabbing the returning DWORD
, which you can then
switch. There are other tutorials here on how to do this, and it's not the
focus of this article to reiterate them. This behaviour is not shown in
the demo project.
Probably the trickiest thing we had to do was get the toolbar outline the
correct size when drawing. It turns out that although MSDN is silent on
the issue, this is done by an object in the toolbar of type CDockContext
, called
m_pDockContext. It keeps track of four LPRECT
structures, and we update
them by firing a timer when we push the left mouse button. We need to
change it both when it is not docked, and when it is docked, so that it always
appears the correct size. When I say always, I have not found a way to
change this rect initially, as I could not override the class successfully and
replace the object in CGSToolBar
with one of our own, and the RECT
's are set in
the BeginDragging
method. The end result is you get an incorrect rect
drawn when you click, but it's correct as you move, and snaps to the outline you
were dragging when finished.