|
Download source files - 18 Kb
See article addenda for more latest updates
Introduction
I guess I know what you're thinking-"Oh no!! Not another toolbar article!". Rest assured that this article discusses something that's most probably not found in any of those handy (dog-eared) MFC/SDK books you've got. It's about a very cool toolbar feature called chevrons. I hope you'll enjoy this, and incorporate the feature into your own code. Adding Chevrons to your code gets your app yet another step towards that elusive professional standard most commercial programs exude.
Chevrons
Version 5.80 of the common control library added support for a cool feature to the rebar control called chevrons. When the length of a band is lesser than the size of it's child control, the rebar displays a chevron to indicate that there's more to show. This feature is particularly useful when there are more bands in the rebar and the user requires more working space in the application. In addition, the user can intuitively see that there are more items that are hidden. This article shows you how to incorporate chevrons and how to handle the same.
To see chevrons at work, fire up IE and resize the window so the width of IE rebar is shrunk to the point it clips some of its items. Now you should see the the chevron(>>), to indicate that some items are not completely visible.

Chevrons can also been seen on the Task bar when you have the quick launch deskband option enabled (Win 98). When the chevron is clicked on, a floating toolbar that has the buttons/options that are not shown in the band appears.
Programming Chevrons
The folks who gave you the common controls have already done much of the work for you. As you might have guessed, there is a flag to activate the chevron style, as well as a handler that's called when the chevron is clicked. Here's how to get it all up and running.
- When adding a band to the rebar control, the flag RBBS_USECHEVRON has to be OR'ed in with the style:
if (!m_wndReBar.Create(this ) ||
!m_wndReBar.AddBar(&m_wndToolBar, NULL, NULL, RBBS_USECHEVRON )||
!m_wndReBar.AddBar(&m_wndToolBar1, NULL, NULL, RBBS_USECHEVRON ))
This code adds two bands capable of supporting chevrons.
- Next, you have to set the size the chevron should be displayed in, when the band grows or shrinks:
REBARBANDINFO rbbi;
CSize sizeBar;
m_wndToolBar.GetToolBarCtrl().GetMaxSize (&sizeBar);
rbbi.cbSize = sizeof(rbbi);
rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE | RBBIM_ID;
rbbi.cxMinChild = 0;
rbbi.cyMinChild = sizeBar.cy;
rbbi.cx = rbbi.cxIdeal = sizeBar.cx;
rbbi.wID = 0;
m_wndReBar.GetReBarCtrl().SetBandInfo(0, &rbbi);
m_wndToolBar1.GetToolBarCtrl().GetMaxSize (&sizeBar);
rbbi.cbSize = sizeof(rbbi);
rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE | RBBIM_ID;
rbbi.cxMinChild = 0;
rbbi.cyMinChild = sizeBar.cy;
rbbi.cx = rbbi.cxIdeal = sizeBar.cx;
rbbi.wID = 1;
m_wndReBar.GetReBarCtrl().SetBandInfo(1, &rbbi);
Note that each band that might display a chevron can have its style modified with the SetBandInfo() call.
The flag RBBIM_IDEALSIZE has to be set so that the ideal size for the chevron can be specified. This flag indicates that the cxIdeal member holds the ideal size of the band. When the band size is reduced below this value, a chevron is shown. You can experiment with this by changing: rbbi.cx = rbbi.cxIdeal = sizeBar.cx;
to rbbi.cx = sizeBar.cx;
rbbi.cxIdeal = sizeBar.cx/2;
You will find that the chevrons are shown only when the size of the band is half the length of the toolbar.
RBBIM_CHILDSIZE specifies the child window size information of the band. For the chevron to appear, at least both the above flags must be specified.
The RBBIM_SIZE flag has been set so that the bands are initially displayed with this size. If you don't use this flag, then the bands won't stay right next to each other-provoking complaints from users!
RBBIM_ID is a very useful and important flag that must be set. Of course, the member wID should also be set to a unique value, so that you can identify the band when required. This is because when users drag the band around, the index of the band keeps changing depending on the current position. But the band id stays with the band no matter where it goes.
NOTE: These two steps are just for convenience, it may be possible to set it all in one go.
Well, at this point your app should display the chevron when required. However, we still aren't done yet; we need to take care of what happens when the user interacts by clicking it. We have to write the handler code. Really, what you do in the event is most likely up to you, but here, we shall go with the most natural behavior!
Assuming CChevBar is derived from CRebar, add a message map for the chevron push event: BEGIN_MESSAGE_MAP(CChevBar, CReBar)
ON_NOTIFY_REFLECT( RBN_CHEVRONPUSHED, OnChevronPushed )
END_MESSAGE_MAP()
Here's the message handler: void CChevBar::OnChevronPushed( NMHDR * pNotifyStruct, LRESULT* result )
{
NMREBARCHEVRON* pChev = (NMREBARCHEVRON*) pNotifyStruct;
int iBand = pChev->uBand;
}
-
The important value that is needed is the uBand member of the structure NMREBARCHEVRON. This identifies the band whose chevron was clicked. Once we have the band id, we can get all the information about the band. Usually, we would need the child window handle.
Chevrons are usually placed when the toolbar is the child window of the band, but of course, this need not always be the case.
What do we do when a chevron is pushed? 99% of the time, we'll be dealing with a toolbar as the child window for the band. So let's stick with this at the moment. Okay, now let's say we wanted to display a popup menu for the items that are hidden when the Chevron is clicked. But how would we find the hidden buttons in the toolbar?
Here's what to do to get those hidden buttons:
- Obtain the band rectangle (subtract chevron width if you want to); let it be R1
- Get the toolbar button rectangle, let it be R2
- Check if the intersecting rectangle of R1 and R2 is same as the R2.
- If they intersect correctly then the button is shown
Of course, this algorithm has to be changed when the child window of the band is not a toolbar.
The simple example application provided along with this article adds the hidden items to an owner drawn popup menu and it displays the popup menu just below the chevron. In the popup menu's drawitem method, the bitmap of the button is extracted from the toolbar's image list and then drawn. The text is extracted from the tip text part of the string resource, which has the same id of the menu item.
Conclusion
Phew! Hopefully by now, you've got a pretty good feel of what chevrons are and how they're implemented. I hope this article has whetted your appetite to find out more and dig in the goodies available in Windows! Happy programming!
Known Problems
As is always the case, there're some issues that haven't been resolved at the moment. If you find out ways of circumventing these problems or have any ideas, I'd appreciate it if you let me know-or better still, post your own article for others to see!
- Toolbar buttons with the drop down style are not handled properly (you can check this with IE, IE does it very nicely). Usually, when the dropdown style toolbar button is clicked another popup menu will be displayed with more options. Since we are using owner drawn menus and there is no way to get a new menu, our application stumbles here L My way of solving this would be to write a custom menu that has buttons. This would send a similar notification to the parent like the toolbar, when its button is clicked.
- Another problem lies in writing reusable code. Rebar is a control, toolbar is another control. The rebar may not have a toolbar as its child in the bands. If so, then how do we write reusable code/class that works for all sorts of different child controls in the rebar?? Go figure.
- I am sure most of you must've worked with BandObjects. When this is the case, how are we notified of the chevron click, and how do we handle it?
- The initial size setting for the band works fine when the toolbar doesn't have any buttons with the style flag TBSTYLE_DROPDOWN. But when a toolbar has one, the GetMaxSize() function seems to return a lesser value. Is there any other way to set the initial size?
Programming Toolbar Chevrons - An Update
Download source files - 8 Kb
Download updated demo project - 26 Kb
This update serves to rectify a few problems arising in the original "Programming Toolbar Chevrons" article. In essence, it's an update on the way the chevron is handled. Primarily, this is as close as you can get to simulate Internet Explorer 5.0's chevron handling.
The original article describes the technique of using a popup-menu to display the hidden buttons in a tool bar. As a result, the dropdown buttons are not handled correctly, as there is no way to know the action of a button down event.
The idea now is to show a popup window that has a toolbar containing the hidden buttons. This ensures that the new toolbar behaves just as the original one.
Let's see how to use project files and save the explanation for later.
The best thing to see chevron at work is the buttons with TBSTYLE_DROPDOWN set. For a sample, applications like word, Outlook express can be checked. When the main window is resized smaller than the toolbar width, the chevron appears, when the chevron is clicked, the toolbar buttons that are with "dropdown" style, also has "dropdown" style in the popup window. A mouse click action on this "popup" toolbar simulate the mouse click in the real toolbar button. This is very convenient when a high "working screen" space is required.

The sample application with this article displays a popup in response to the chevron click.

Lets see how it all goes...
Its code time
The idea is simple:
- Create a popup window
- Create a toolbar with the popup as the parent and add the hidden buttons to it
- Show the popup window just below chevrons
- Handle messages in the pop-up window sent by the toolbar. Redirect them if necessary
However, as usual, the implementation of the idea gets rather challenging:
The first thing to see is the CChevBar::OnChevronPushed() member. This is called by the framework when a chevron button is clicked. In response to it we have to check if the child window is really a toolbar (at this point, we don't know how to handle bands with other controls in it). If it is a toolbar a new CChevDrop is created-it is this CChevDrop object that drives the rest of the program.
CChevDrop::ShowPopup() is the next function that is called which:
- Creates the popup window
- Creates the toolbar inside this popup window
- Copies the image list from the real toolbar to the one in popup
- Inserts the hidden buttons from the real toolbar to the one in popup
And that's it! Your chevron popup is now displayed. But hang on to your hats - it won't start working immediately. This is because the toolbar sends all the messages to the parent, which happens to be the popup window. Hmmm… what if we tell the toolbar to send the notifications to the frame window itself ?? Yes, that works fine, but the popup won't go away once you click the toolbar button. Therefore, you've got to handle the notifications in the popup and send only the required ones to the parent frame. All these are tabulated as follows, for your convenience:
| Condition |
Action required |
| A button in the toolbar was clicked |
The toolbar sends a command message to the parent.
This means an action is going to be taken and our popup window with the toolbar has to be closed. So pass the command message to the parent frame and close/destroy our popup window. |
The dropdown arrow was clicked for the button with TBSTYLE_DROPDOWN |
The toolbar sends a notification message to the parent.We have to redirect the notification to the parent frame to let it handle. Typically the parent frame handler shows another popup menu full of options. We should not close the popup |
| A mouse button click anywhere outside our popup menuOr The escape key was pressed |
We have to close the popup menu |
That's all that's required to handle the chevron popup
A few problems (uh oh, here we go again):
- For the chevrons to show up correctly, the ideal size of the band has to be set. But it was difficult to find the size of the toolbar properly when the toolbar has buttons with the
TBSTYLE_DROPDOWN style enabled.
CToolBarCtrl::GetMaxSize() returns the correct size of the toolbar when the toolbar has NO TBSTYLE_DROPDOWN buttons. But it always seems to return something smaller than the actual size when the buttons have TBSTYLE_DROPDOWN style enabled. It looks like the width of TBSTYLE_DROPDOWN style buttons are not taken into account.
Another attempt of mine was to obtain the item rectangle for the first and last buttons. From this, the size of the toolbar can be calculated. But this too doesn't seem to work. The returned size was less than the actual size.
Yet another try was to use CToolBarCtrl::SetRows(CtoolBarCtrl::GetRows(), FALSE, &rectTool), but it's a sad thing that it didn't work too.
If anybody gets around the way to find the size of the toolbar, please comment on it or please refer me to it. I'd very much appreciate it.
- Usually the menu scrolls ( "Animates" ) to display its contents, but this functionality has not been implemented at the moment. This is left to the reader as an exercise (wicked grin).
- Usually when a popup menu is shown, the main window(or parent) is not deactivated... But in this case it is deactivated. A problem might occur when the parent frame does not expect this to happen...
A few final words:
The code has been commented with the drawbacks and workarounds. If you think there's a better way to reach the same goal, please do post it. It would helpful for all.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 74 (Total in Forum: 74) (Refresh) | FirstPrevNext |
|
 |
|
|
Hi, Can a gripper be inserted into the toolbar to resize a toolbar item left side of the gripper like google toolbar gripper that resizes the search combobox. Please tell the solution if anyone know. Any programming language is welcomed and C# is great plus as required by me. Please make email the solution at rizwan_nuces@yahoo.com Thanks Rizwan
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
First, let me say this is a greate article and the code it's verry well written.
I've noticed that the IE chevron poped up menu it's not quite keyboard navigation friendly, it's not quite what you would expect from a regular menu which we all know it isn't. For example if there's a sub menu you can't use left & right keys to go back and forwad. There are limitations to this fake menu. I've found that your idea of poping up a toolbar like ui insted of a menu like ui works much better because the user would not be confused.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Anybody can help me with this?
thanks,
Marcelo Calado
Do you need develop a Professional Software with low cost? Contact me!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I set the USER-Key "ToolBandWidth" in "Software\\Microsoft\\Internet Explorer\\CommandBar" to avoid such problems.
Greetings from Germany
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I am using VC 6.0. When I am trying to compile, I got the following error. Is there any thing missing or to be included.
error C2065: 'NMREBARCHEVRON' : undeclared identifier Thank you
|
| Sign In·View Thread·PermaLink | 1.20/5 (2 votes) |
|
|
|
 |
|
|
Hi, The code you have shared is awesome. I am having a slight problem. The Chevron button is parially displaying tsome buttons. But if we observe it in internet explorer then it does not display button partially when we resize the explorer. Either the buttons are displayed fully or not at all in the toolbar. So how can we acheive this kind of functionality.
Tushar
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
Hi...I have a problem with subclassing the internet explorer main window. I would like to do this in order to catch RBN_CHEVRONPUSHED message. I have made a class derived from CWindowImpl in which I put NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed). On the SetSite method: HWND hWnd; m_spWebBrowser->get_HWND((long*)&hWnd);
m_myWindow.SubclassWindow(hWnd);
It seems I never receive RBN_CHEVRONPUSHED. What I'm a doing wrong?
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Hello again....I solved the problem....I was subclassing the wrong window...Actually it is not the main internet explorer window who receives RBN_CHEVRONPUSHED but the parent window of the CReBar control which is a worker window. So...first find the CReBar window and the subclass it's parent. Hope this will others in need .
|
| Sign In·View Thread·PermaLink | 3.00/5 (2 votes) |
|
|
|
 |
|
|
Hi.
At first I would like to thank you for the good article, nice work.
I would like to know something about the OnNotify-function. How can I catch with the code, which one of the options ("Sample 1", "Sample 2",etc.) was pressed.
Thank You!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Dear Rajasekar,
Thanks for the nice code! Do you think its possible to add some nice pictures to the OnNotify function, so that there is not only a plain text like "Sample 1","Sample 2" etc. displayed?
Thanks.
-- modified at 21:37 Sunday 26th November, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
In IE or other APP, when the chevron was clicked twice consecutively without menu tracking, the popup menu/wnd should be closed. That is: The first click activate the popup. The second click deactivate the popup and all status come back to normal.
I try to do check in On..Pushed function but failed. How can it be solved.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
it's very good code ,but i want the toolbar can "EnableDocking(CBRS_ALIGN_ANY);",what can i reslove it?? like office 2000 word. hawhaw
-- modified at 3:32 Wednesday 17th May, 2006
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Is there any way that I can access the Microsoft office Aommandbar chevron by using an addin?
--- With best regards, A Manchester United Fan
The Genius of a true fool is that he can mess up a foolproof plan!
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
I can't used chevron in Outlook. Can you help me?
When i click new mail. I have 5 buttons. It have some events. If 1 in 5 buttons to hide when i resize window again. It put to chevron Office. Then it lost events. I can't to draw chevron. Can't you help me.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The buttons on my toolbars contain only text, so no imagelist. Can someone give me information about how to change this solution without using the imagelist for this.
The problem with the current code resides in the MeasureItem and DrawItem. I tried to remove the imagelist related code, but got errors in other windows classes.
greets, tim
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello, I have an IE toolband with iconic dropdown buttons. The problem is that icons are not visible in the chevron menu , although they appear on dropdown buttons. I have subclassed IE rebar, so I use standard chevron menu ( I don't display mine ). Can anyone tell me what must I do, to show icons on chevron menu?
|
| Sign In·View Thread·PermaLink | 1.80/5 (2 votes) |
|
|
|
 |
|
|
subclassed IE rebar is wrong, because IE Windows process RBN_CHEVRONPUSHED message is not in IE rebar windows. The correct way is subclass IE rebar's parent windows (the IE Worker32W windows), at here, process WM_NOTIFY message and get RBN_CHEVRONPUSHED call, like this:
IEFrame -> Work32W -> ReBarWindows32 -> Your IE ToolBar
(You can use spy++ to inspect IE window)
I'm Guozi
|
| Sign In·View Thread·PermaLink | 4.00/5 (1 vote) |
|
|
|
 |
|
|
I'm programming a toolbar for IE. I'm naturally using a toolbar control as a child window.
My problem is simple, whatever I do, the chevron is NEVER shown.
I've played with all possible combinations of values returned by GetBandInfo.
Description of the CONDITION for the chevron to appear in MSDN is rather poor and uncertain (in my opinion). The only thing I've found there is that the containing rebar control must be created with a special flag, but I assume IE does it for me (other toolbars have chevrons). As far as I understand, from the toolbar perspective the only condition is that current size is smaller than the toolbar's ideal size ( ideal size is returned upon pdbi->dwMask & DBIM_ACTUAL ) Please correct me if I'm wrong.
Maybe there are some non-trivial conditions which must be fulfilled.
Any Ideas? Please, help...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm programming a toolbar for IE. I'm naturally using a toolbar control as a child window.
My problem is simple, whatever I do, the chevron is NEVER shown.
I've played with all possible combinations of values returned by GetBandInfo.
Description of the CONDITION for the chevron to appear in MSDN is rather pure and uncertain (in my opinion). The only thing I've found there is that the containing rebar control must be created with a special flag, but I assume IE does it for me (other toolbars have chevrons). As far as I understand, from the toolbar perspective the only condition is that current size is smaller than the toolbar's ideal size ( ideal size is returned upon pdbi->dwMask & DBIM_ACTUAL ) Please correct me if I'm wrong.
Maybe there are some non-trivial conditions which must be fulfilled.
Any Ideas? Please, help...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
| | |