Click here to Skip to main content
15,881,248 members
Articles / Desktop Programming / MFC
Article

Setting the row count of a tool bar

Rate me:
Please Sign up or sign in to vote.
4.90/5 (7 votes)
24 Nov 20012 min read 89.4K   1.7K   28   6
Floating a CToolBar with a given number of rows to be displayed is tricky

Sample Image

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:

Image 2

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:

Image 3

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<br>

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();
}

Image 4

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 :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Germany Germany
PhD Chemist,
programming with MSVC & MFC since 1996

Comments and Discussions

 
QuestionLICENSE TO USE THE CODE Pin
Kartik M29-Jan-18 2:25
Kartik M29-Jan-18 2:25 
GeneralSuper Cool! Super Thanks! Pin
Gautam Jain15-May-06 1:30
Gautam Jain15-May-06 1:30 
GeneralThis is great Pin
wangdt11-Nov-04 6:32
wangdt11-Nov-04 6:32 
QuestionHow about without MFC? Pin
5-Dec-01 4:59
suss5-Dec-01 4:59 
AnswerRe: How about without MFC? Pin
Thomas Blenkers7-Dec-01 11:53
Thomas Blenkers7-Dec-01 11:53 
GeneralRockin! Pin
Swinefeaster26-Nov-01 20:46
Swinefeaster26-Nov-01 20:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.