Click here to Skip to main content
Click here to Skip to main content

Ribbon-style Two-level Tab Bar for Dialog Boxes in WTL

By , 7 Apr 2009
 
sample-dialogs.png

Introduction

I created this simple and attractive two-level tab bar for use exclusively in dialog boxes. It can be used to improve property pages and dialog-based applications.

This project was developed using Microsoft Visual C++ 2008. It requires WTL 8 and GDI+. It was tested on Windows XP, Windows Vista, and Windows 7 Beta 1.

Inspiring the Look

I took a screenshot of the Microsoft Office Word 2007 Ribbon bar and played with it in Paint to come up with a simplified Ribbon interface:

office-ribbon.png

But there are many examples of two-level tabs, so I put together some of my favorites:

inspiration.png

The things I like from the above are:

  • the look of the selected first-level tab (tab) in (1), (5), and (6)
  • the look of the selected second-level tab (sub-tab) in (4) and (6)
  • the icons in (1)
  • the gradient fills in (4)
  • the simple hot-tracking in (2) and (5)

But I also wanted:

  • the tabs on "glass" – at least on Vista and better. There should only be a background fill when the Desktop Window Manager (i.e., Aero) is not available.
  • the icon in the selected sub-tab only to be in color. The other icons could be recolored (specifically, toned) to the tab color – I call this, "color-washing" the icons.
  • to be able to change the colors easily.

Design Decisions

Windowless Control

The code extends the top of the non-client area by the height of the tab bar. The "sheet of glass" is extended onto this area. The tabs are drawn entirely on the non-client area.

Draw with GDI+

All of the drawing is done with the help of GDI+. I did not want to use bitmaps, because I wanted to be able to easily change the colors of my ribbon tab bar.

The only graphics needed are optional icons for the sub-tabs. Only full color icons are necessary. GDI+ is used to color-wash the icons (for unselected sub-tabs). Color-washing basically:

  1. converts the icon to grayscale; and
  2. adds color to the icon

It is accomplished easily with a ColorMatrix.

Animation

I wanted a subtle animation (dissolve/cross-fade) when the state changed, i.e., when an item was hot-tracked, or the tab or sub-tab selection changed. This is easily accomplished in Vista or better with BeginBufferedAnimation/EndBufferedAnimation.

Now, BeginBufferedAnimation expects you to draw the initial state and the final state in an animation, and it will take care of drawing the intermediate frames. That is what is done in the sample in the MSDN documentation for BeginBufferedAnimation. However, I discovered (quite by accident!) that if I delete the DC hdcFrom (that is, DeleteDC(hdcFrom)) returned by BeginBufferedAnimation, then Windows will auto-magically use what is already drawn as the initial state, so I only needed to draw the final state. That saved me from having to deal with caching or re-drawing an initial state every time the state changed.

Keyboard Control

The standard tab control can be controlled with the keyboard arrow keys. If the tab is in a property sheet, then there is some awkward (in my opinion) tabbing from the tabs back to the pages.

I wanted to keep it simple, so I decided that tabs should have access keys. For example, the tab "&Properties" is displayed, initially, without the "p" mnemonic ("Properties"). After the user presses the ALT key, the mnemonic is underlined (“Properties”). Pressing ALT+P will select the Properties tab. When Properties is the active tab, its "p" is no longer a mnemonic - after all, one cannot re-select an already selected tab. That means that "p" can be used again, either in another tab or a sub-tab. This functionality helps to reduce mnemonic collisions.

To get this functionality, all I needed to do was generate an accelerator table and then let TranslateAccelerator do its job (in PreTranslateMessage). The accelerator table is updated every time the selection changes.

Using the Code

Include RibbionDialog.h and derive a dialog box from CRibbonDialogImpl (instead of CDialogImpl). Then, add CHAIN_MSG_MAP(CRibbonDialogImpl<...>) to the beginning of your message map.

Adding Tabs and Sub-Tabs

To add a tab, just call AddTab with a string resource ID. To add a sub-tab, call AddSubTab with a string resource ID and an optional icon resource ID – the sub-tab will be added to the last tab. For example:

// Add a tab
AddTab(ID_TAB1);

// Add two sub-tabs to TAB1
AddSubTab(ID_TAB1SUBTAB1, IDI_ICON1);
AddSubTab(ID_TAB1SUBTAB2, IDI_ICON2);

// Add another tab
AddTab(ID_TAB2);

// Add three sub-tabs to TAB2
AddSubTab(ID_TAB2SUBTAB1, IDI_ICON3);
AddSubTab(ID_TAB2SUBTAB2, IDI_ICON4);
AddSubTab(ID_TAB2SUBTAB3, IDI_ICON5);

You have to add at least one tab, and every tab must have at least one sub-tab.

Handling the Notification of the Changed Selection

The string resource IDs also function as command identifiers. When a selection changes, you will receive a WM_COMMAND notification message. Use COMMAND_ID_HANDLER or MSG_WM_COMMAND in your message map to handle these messages:

BEGIN_MSG_MAP_EX(CMainDlg)
    CHAIN_MSG_MAP(CRibbonDialogImpl<CMainDlg>)
    MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
    ...
        COMMAND_ID_HANDLER(ID_TAB1SUBTAB1, OnTab1Subtab1Selected)
    MSG_WM_COMMAND(OnCommand)
    ...
END_MSG_MAP()

(The low-order word of wParam will be the string resource ID of the selected sub-tab. The high-order word of wParam will be 0.)

Changing the Colors

Just change the color constants in the header file to modify the look of your ribbon tab bar.

About the Sample Application

The sample application shows how the ribbon tab bar could be used in a re-sizable dialog box. When a dialog is re-sized, you'll notice that:

  1. there is no flicker; and
  2. animation is temporarily turned off

Final Remarks

I tried to follow the KISS principle, and I believe this project is, indeed, simple – but still functional and beautiful. I hope you think so, too. :-)

History

  • Apr 6, 2009
    • Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Raj Pabari
Software Developer
Canada Canada
Member
Raj collects postcards. He has been known to wear a bow tie on occasion. He's an optimist.
 
"Don't take life too seriously. You'll never get out alive." ~ Elbert Hubbard

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralC++ <> VB.NET [modified]memberPaul van der Stel19 Jan '12 - 7:05 
At first of all, I LOVE IT!!!
 
My version of Visual Studio (2010 Prof.) gets a ton of errors when I open the project.
Can't you upload a compiled .dll file so i can insert it to my toolbox or else, can you tell me how i can open it in VB.NET.
 
Paul.

modified 2 Jul '12 - 11:25.

AnswerRe: C++ VB.NETmember0Question-Mark029 Jan '12 - 9:52 
Same from here. You did an awesome job!
 
I also would appreciate a .dll or an other way to insert this awesome piece of code in my Vb.net project.
 
Thx in advance.
Questionhow to use it in a vc6 project?memberkoala_wk4 Aug '11 - 21:10 
how to use it in a vc6 project?
www

Generalhow to?memberpophelix11 May '11 - 18:19 
怎么动态添加一个tab?
如:我在add(sub1)添加子tab忘记了,想在add(sub2)后面添加一个sub1的子tab,我该怎么做?
 
是否能改成:add(child_sub,parent_subid);当parent_subid为NULL时,我们就当它为根节点?
例如:
// Add a tab
AddTab(ID_TAB1);
AddTab(ID_TAB2); Smile | :)
 
// Add two sub-tabs to TAB1 TAB2
AddSubTab(ID_TAB1SUBTAB1, ID_TAB1,IDI_ICON1);
AddSubTab(ID_TAB1SUBTAB2, ID_TAB2 ,IDI_ICON2);
 
这样是不是更合理一点?
GeneralRe: how to?memberpophelix12 May '11 - 4:12 
//添加指定uID的子tab
void AddSubTab2(UINT uID, UINT uIconResID /* = 0 */,UINT uParent_uID = 0)
{
int iTabCount = m_listTabs.GetCount();
int iTabId = 0;
 
for (int i = 0, iTabCount = m_listTabs.GetCount(); i < iTabCount; i++)
{
if (m_listTabs[i].uID ==uParent_uID)
{
iTabId;
}
break;
}
 
RIBBONDLGTAB subtab = {0};
subtab.uID = uID;
subtab.uIconResID = uIconResID;
 
// Default: First sub-tab should be selected
if (m_listTabs[iTabId].listSubtabs->GetCount() == 0)
subtab.uState = RD_TST_SELECTED;
 
m_listTabs[iTabId].listSubtabs->Add(subtab);
}
 

 
test ok!
 
// Add tabs
AddTab(IDS_TAB1);
AddSubTab(IDS_TAB1SUBITEM1, IDI_ICON2);
//AddSubTab(IDS_TAB1SUBITEM2, IDI_ICON1); Frown | :(
 
AddTab(IDS_TAB2);
AddSubTab(IDS_TAB2SUBITEM1, IDI_ICON4);
AddSubTab(IDS_TAB2SUBITEM2, IDI_ICON6);
AddSubTab(IDS_TAB2SUBITEM3, IDI_ICON7);
 
AddSubTab2(IDS_TAB1SUBITEM2,IDI_ICON1,IDS_TAB1); Wink | ;)
General.NETmemberPascalPCFreak8 Jan '11 - 9:38 
Is there a possibility to use this in .NET projects?
GeneralThe others style colors / Have it in the client areamembermidiway18 Dec '09 - 9:06 
Hi
 
1. Could you please tell me what are the colors that you defined to get the visual seen in the others screenshoots?
 
2. I want to put some controls above this tab bar, so I would need it placed inside the client area, is it possible? Why you made it in the non-client area?
GeneralRe: The others style colors / Have it in the client areamemberRaj Pabari1 Feb '10 - 9:05 
Hello, there!
 
For #1: No. I recommend that you experiment (like I had to!) and try our different colours and combinations. It's fun (mostly). You may want to start at COLOURlovers.
 
For #2: Sure, it's possible. Feel free to adapt the code as you wish for your specific needs. It was simply one of my Design Decisions was to make it windowless and put the control in the non-client area.
 
Have fun! Smile | :)
Generalreally coolmember64bit5 Sep '09 - 0:34 
good job, really cool!
GeneralNice jobmemberReza Jahanbakhshi4 Jun '09 - 23:40 
Thanks,
I'll definitely consider using it.
5 from me.
 
Again thanks.
 
There is no knowledge, That is not power.

GeneralWriting on glass!memberAlireza Noori24 May '09 - 11:26 
Hi,
Very good article.
I had a question from you. I searched all over internet, I couldn't find how to find on glass area of windows in vista the way you did here (I mean with a white blurry background). First I saw this in Microsoft-Specific programs like Media Player, but I couldn't find the way to do it.
The thing is, I want to do this in a managed application (for example with C#). Could you please help me?
Thanks in advance.
GeneralRe: Writing on glass!memberRaj Pabari25 May '09 - 9:06 
Alireza Noori wrote:
Very good article.

Thanks.
 
Alireza Noori wrote:
I had a question from you. I searched all over internet, I couldn't find how to find on glass area of windows in vista

I recommend that you try searching again, because there is a lot of info out there, including on CodeProject.
 
For example, this aptly named article, right here on CodeProject, might help you: Drawing smooth text and pictures on the extended glass area of your WinForm in Windows Vista[^].
GeneralRe: Writing on glass!memberAlireza Noori26 May '09 - 6:45 
A million thanks. I searched for this a long time ago. At that times I couldn't find it.
Very, very thanks.
NewsGuidlinesmemberKevin Robert Phelps15 Apr '09 - 17:16 
This ribbon is does not follow the Office 2007 Fluent UI Guidlines. In order to use the Office 2007 UI (ribbon), you must agree to the Office 2007 UI License.
GeneralRe: GuidlinesmemberRaj Pabari16 Apr '09 - 6:42 
Microsoft does not own the concept of a ribbon[^]. Of course, the term ribbon has been popularized by Microsoft with their Office Fluent User Interface[^].
GeneralRe: Guidlines [modified]memberKevin Robert Phelps17 Apr '09 - 13:09 
Actually, Microsoft does own several patents on the ribbon style UI, effectivley owning the ribbon UI. Microsoft does not have to allow third parties to use thier innovative UI, however they are. In order use a ribbon UI, you do must two things:
1. Sign the Office 2007 Fluent User Interface license
2. Follow the Design Guidlines exactly
I have read all 119 pages of the Design Guidlines and the full license, so I know what I am talking about. This ribbon implementation does not adhere to the license. I am not offending you of anyone on this project; I am just warning that Microsoft will not allow this style of ribbon in a final product.
 
modified on Friday, April 17, 2009 9:44 PM

GeneralRe: GuidlinesmemberRaj Pabari17 Apr '09 - 14:29 
Kevin Robert Phelps wrote:
In order use any sort of ribbon

That is absolutely incorrect. There can be many different kinds of ribbons. Ribbons were in use before Office 2007. The Office UI is just a specific kind of ribbon.
 
The "ribbon" in this article is not an attempt at an implementation of the Office UI design. Take a quick glance at the article, and you'll see it's not even close.
 
So any Microsoft licenses/patents simply do not apply here. Cool | :cool:
GeneralNicely done!memberErnest Laurentin13 Apr '09 - 13:04 
5+ from me!
 

Try not to become a man of success but rather to become a man of value. - Albert Einstein
Ernest Laurentin

GeneralIt's cool!membertsehonkit10 Apr '09 - 16:57 
I also read another working example from http://www.viksoe.dk/code/iconpacksample.htm for reference.
GeneralRe: It's cool!memberStoney Tian15 Apr '09 - 13:06 
thanks
 
http://www.viksoe.dk/code/iconpacksample.htm
 
both are great.
 
My Homepage : http://blog.csdn.net/accesine960
 
china,beijing

GeneralRe: It's cool!memberpophelix11 May '11 - 22:45 
cool!
GeneralVery impressive !!memberfred7910 Apr '09 - 11:28 
One of the best I've seen. Right up there with Hans' work.
 
Regarding those who want a C# version....Ladies and Gentlemen, regardless if it's .NET, MFC, Win32, or WTL they are all ultimately doing the same thing. If you want to take your programming to the next level you should be able to read an article and regardless of the programming language be able to say to your self "Oh, there's a bitmap...oh he's using anti-aliasing....ok...I see he's scaling the icons, etc".
 
End of rant.
 
Great job Raj!
GeneralRe: Very impressive !!memberRaj Pabari10 Apr '09 - 11:55 
fred79 wrote:
One of the best I've seen. Right up there with Hans' work.

 
Aw, shucks... thanks! Big Grin | :-D
GeneralNice LookmemberFlynn Arrowstarr8 Apr '09 - 7:49 
Hey, Raj.
 
This looks very nice. Shucks | :->
 
Flynn
 

GeneralRe: Nice LookmemberRaj Pabari8 Apr '09 - 12:08 
Thanks! I'm glad you like it.

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 7 Apr 2009
Article Copyright 2009 by Raj Pabari
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid