Setting the row count of a tool bar






4.90/5 (7 votes)
Nov 25, 2001
2 min read

90352

1672
Floating a CToolBar with a given number of rows to be displayed is tricky
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:
/* Lets float one of our toolbars but make sure that is has the desired row count. if the count is too small to be set, then return the row count used. Parameters: pToolbar - Pointer to the MFC tool bar object to be manipulated nRows - Requested number of rows
bLarger - Tells whether to use more rows or fewer rows if the toolbar cannot be resized to the requested number of rows. (for details see CToolBarCtrl::SetRows in the MSDN documentation) pClient - Pointer to a CPoint object for the position int client coordinates for the toolbar to appear floated. If this Parameter is NULL, the default upper left corner of "this" window will be used Returns: The value of the function CToolBarCtrl->GetRows after the resizing has occured. A simple experiment shows,but this is NOT the real number of rows displayed :( */ int CMainFrame::FloatToolbarSetRows( CToolBar *pToolbar, int nRows, BOOL bLarger, CPoint *pClientPos) { // default upper left corner // of the floating toolbar // is upper left corner of main wnd CPoint newPos(0,0); // if other pos specified, use it if (pClientPos) newPos = *pClientPos; // functions use screen coords ClientToScreen(&newPos); // first, make sure our toolbar is floating if (!pToolbar->IsFloating()) FloatControlBar(pToolbar, CPoint(0,0)); // now set the desired row count // may result in more rows than specified // see the MSDN docs: CToolBarCtrl::SetRows // // this function also calculates the new // toolbar window size // unfortunately this function only arranges // the toolbar buttons, but will not update // the size of the tool bar window ... CRect rcNew; pToolbar->GetToolBarCtrl().SetRows(nRows, bLarger, &rcNew); // we need to reset the horizontal extend // of the toolbar before it "knows" its // width. It will not diplay this width // before the window is touched by us (or // by the mouse) pToolbar->CalcDynamicLayout(rcNew.Width(), LM_HORZ | LM_COMMIT); // now move the window to the desired position 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 :)