Introduction
In my recent project - a simple multiplayer network game - I needed a very large
toolbar (21 buttons), surely taking some width on the screen :) So one really
wet and cold German November Sunday I wondered if it would be possible to create
it neatly arranged in a floated toolbar:
Should be simple, I thought. But it kept me experimenting and digging the rest
of the day and encountering a bug in the toolbar control (at least under my
Win98 SE, IE 5.5) ...
Regarding the MSDN docs you should look at the CToolBarCtrl::SetRows
function,
that says - "ask the toolbar control to resize itself to the requested
number of rows". Lets hope the toolbar is polite enough to do so.
Of course, it isn't. When you do something like :-
CRect rcNew;
m_wndJewelBar.GetToolBarCtrl().SetRows(5, TRUE, &rcNew);
The buttons are rearranged like in the picture above, but the toolbar window
itself stays the same lengthy same, whether docked or not:
Fortunately the rcNew
rectangle returned is correct. Now I could use it to
reset the width of the toolbar:
m_wndJewelBar.CalcDynamicLayout(rcNew.Width(), LM_HORZ | LM_COMMIT);
But: nothing seems to have happened - until I touched the toolbar with the
mouse: magically it popped into the correct size: you have to move the toolbar
window before it redraws itself the the correct shape. And for moving the toolbar
there is the function
CFrameWnd::FloatControlBar(&m_wndJewelBar, rcNew,
CBRS_ALIGN_TOP | CBRS_SIZE_DYNAMIC);
Code listing
Pretty weird, isn't it? Now, I put things together and made a little function
for this:
int CMainFrame::FloatToolbarSetRows(
CToolBar *pToolbar, int nRows, BOOL bLarger,
CPoint *pClientPos)
{
CPoint newPos(0,0);
if (pClientPos)
newPos = *pClientPos;
ClientToScreen(&newPos);
if (!pToolbar->IsFloating())
FloatControlBar(pToolbar, CPoint(0,0));
CRect rcNew;
pToolbar->GetToolBarCtrl().SetRows(nRows,
bLarger, &rcNew);
pToolbar->CalcDynamicLayout(rcNew.Width(),
LM_HORZ | LM_COMMIT);
FloatControlBar(pToolbar, newPos,
CBRS_ALIGN_TOP | CBRS_SIZE_DYNAMIC);
return pToolbar->GetToolBarCtrl().GetRows();
}
Conclusion
There are two known bugs in this code, but I would like to blame Windows for this:
- My function is to return the actual number of rows in the tool bar. This
is wrong. In my 21 button toolbar, I tell the function to create 5 rows, which
it does, but
GetRows()
returns 9 - ouch! If you really care
about the new
size, you may calculate it by using the new toolbar window rectangle height
and divide it by the toolbar button size. - When you resize my toolbar to having 11 rows, the last group of four buttons
is wider than the toolbar width of 3. The last button of the group will not
be displayed (see image above). Since I can duplicate this behavior by manually
floating and resizing the toolbar, I decided not to care about this, and think
the Redmondians are fooling me.
At last (and least) have fun with this code. May there be a fine day you find
the finished game on my homepage :)