Click here to Skip to main content
11,482,402 members (75,038 online)
Click here to Skip to main content

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

, 7 Apr 2009 CPOL 119K 7.6K 162
Rate this:
Please Sign up or sign in to vote.
A simple, functional, and attractive windowless control to jazz up your dialog boxes
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. Smile | :)

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)

Share

About the Author

Raj Pabari
Software Developer
Canada Canada
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

Comments and Discussions

 
GeneralC++ <> VB.NET [modified] Pin
Paul van der Stel19-Jan-12 8:05
memberPaul van der Stel19-Jan-12 8:05 
AnswerRe: C++ VB.NET Pin
0Question-Mark029-Jan-12 10:52
member0Question-Mark029-Jan-12 10:52 
Questionhow to use it in a vc6 project? Pin
koala_wk4-Aug-11 22:10
memberkoala_wk4-Aug-11 22:10 
Generalhow to? Pin
pophelix11-May-11 19:19
memberpophelix11-May-11 19:19 
GeneralRe: how to? Pin
pophelix12-May-11 5:12
memberpophelix12-May-11 5:12 
General.NET Pin
PascalPCFreak8-Jan-11 10:38
memberPascalPCFreak8-Jan-11 10:38 
GeneralThe others style colors / Have it in the client area Pin
midiway18-Dec-09 10:06
membermidiway18-Dec-09 10:06 
GeneralRe: The others style colors / Have it in the client area Pin
Raj Pabari1-Feb-10 10:05
memberRaj Pabari1-Feb-10 10:05 
Generalreally cool Pin
64bit5-Sep-09 1:34
member64bit5-Sep-09 1:34 
GeneralNice job Pin
Reza Jahanbakhshi5-Jun-09 0:40
memberReza Jahanbakhshi5-Jun-09 0:40 
GeneralWriting on glass! Pin
Alireza Noori24-May-09 12:26
memberAlireza Noori24-May-09 12:26 
GeneralRe: Writing on glass! Pin
Raj Pabari25-May-09 10:06
memberRaj Pabari25-May-09 10:06 
GeneralRe: Writing on glass! Pin
Alireza Noori26-May-09 7:45
memberAlireza Noori26-May-09 7:45 
News-- [modified] Pin
Kevin Robert Phelps15-Apr-09 18:16
memberKevin Robert Phelps15-Apr-09 18:16 
GeneralRe: Guidlines Pin
Raj Pabari16-Apr-09 7:42
memberRaj Pabari16-Apr-09 7:42 
GeneralMessage Removed Pin
Kevin Robert Phelps17-Apr-09 14:09
memberKevin Robert Phelps17-Apr-09 14:09 
GeneralRe: Guidlines Pin
Raj Pabari17-Apr-09 15:29
memberRaj Pabari17-Apr-09 15:29 
GeneralRe: Guidlines [modified] Pin
umeca7431-Oct-14 3:51
memberumeca7431-Oct-14 3:51 
GeneralNicely done! Pin
Ernest Laurentin13-Apr-09 14:04
memberErnest Laurentin13-Apr-09 14:04 
GeneralIt's cool! Pin
tsehonkit10-Apr-09 17:57
membertsehonkit10-Apr-09 17:57 
GeneralRe: It's cool! Pin
Stoney Tian15-Apr-09 14:06
memberStoney Tian15-Apr-09 14:06 
GeneralRe: It's cool! Pin
pophelix11-May-11 23:45
memberpophelix11-May-11 23:45 
GeneralVery impressive !! Pin
fred7910-Apr-09 12:28
memberfred7910-Apr-09 12:28 
GeneralRe: Very impressive !! Pin
Raj Pabari10-Apr-09 12:55
memberRaj Pabari10-Apr-09 12:55 
GeneralNice Look Pin
Flynn Arrowstarr8-Apr-09 8:49
memberFlynn Arrowstarr8-Apr-09 8:49 

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

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

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