A visual upgrade is often welcome. Aside from the aesthetics, it also helps to introduce new features and new ways to complete tasks. Microsoft made such a move with the launch of its Office Suite 12. In this, they launched the ribbon. If you're interested in making your application compatible with the ribbon, keep reading.
Contributed by Gabor Bernat Rating: / 2 October 27, 2009
The ribbon is the result of a massive amount of customer research that Microsoft conducted. Over the past few years, the ribbon has managed to redefine how we interpret Office applications -- and to be honest, most of us have become addicted to its context-sensitive toolbar system.
This article is the second part of a two-part series in which I am looking into how to upgrade/extend your old-school application. The title of the first part is New Features for the Statusbar in MFC and you can find it here on the ASP Free section of the Developer Shed network. In the first part, I showed how to apply the Office style to your application. In this second part, I will show how to add the new tab-based multi-window system and how to add a ribbon to your application.
I will stick with the XML Explorer source code and continue its improvement and extension. Adding the tab support is one of the simplest tasks. First, you need to make sure that in the Application class on the initialization of the instance, the InitContextMenuManager () method is called. This will create the object that will handle future tasks; I have already done this in the first task.
Now we just need to tell the application to use the style. The CMDTabInfo is a class through which you can customize how to perform these tasks. Pass it after you build it as an argument as shown below:
CMDITabInfo tabInfo; // Declare the object
//customize it
tabInfo.m_bAutoColor = true;
tabInfo.m_bDocumentMenu = true;
//pass it for the Manager
EnableMDITabbedGroups (true, tabInfo);
Now, once you run the application, you can observe it in action:
The table below will explain the other configuration options of the tab system:
CMDITabInfo Member
Value options and effects
m_style
STYLE_3D -3D style.
STYLE_3D_ONENOTE - Microsoft OneNote style.
STYLE_3D_VS2005 - Microsoft Visual Studio 2005 style.
STYLE_3D_SCROLLED - 3D style with rectangle tab labels.
STYLE_FLAT_SHARED_HORZ_SCROLL - Flat style with shared horizontal scroll bar.
STYLE_3D_ROUNDED_SCROLL - 3D style with round tab labels.
m_bActiveTabCloseButton
FALSE => Place close button at right of the tab area.
m_bTabIcons
TRUE => enable document icons on MDI tabs.
m_bAutoColor
Enable or disable the auto color.
m_bDocumentMenu
TRUE => Enable document menu at the right edge of the tab area.
m_bEnableTabSwap
User can change (or not change) the positions of the tabs by dragging them.
m_bFlatFrame
TRUE => give each tab window a flat frame.
m_bTabCloseButton
TRUE => each tab displays a close button on the right edge of the tab.
m_bTabCustomTooltips
TRUE => tabs display tooltips.
m_tabLocation
LOCATION_BOTTOM: the tabs; labels are located at the bottom of the page.
LOCATION_TOP: the tabs' labels are located at the top of the page.
m_nTabBorderSize
Specifies the border size, in pixels, of each tab window.
Making applications using the new Ribbon system is certainly not an easy task. I'm not saying that it is very complicated and that it requires heavy documentation. The problem is that Microsoft obligates (or at least it did at the beginning) any company using the product of their research (for commercial purpose at least) to sign the Ribbon Fluent Guidelines.
Microsoft also filled a patent application form for it. No patent has been issued so far. It is debatable that the Ribbon has its origins in the tabbed toolbars of applications such as Macromedia HomeSite, Dreamweaver and Borland Delphi. Possibly because of this, the Office Fluent Guidelines (which try to create a consistent user experience with the ribbon) have recently been published on the MSDN here.
Meanwhile, the software giant from Redmond has also developed a framework for the Ribbon. I will talk about this in future articles. This tries to make using the ribbon in applications easier and accessible to more people. Support for both C++ and C# is present. However, for now I am going to stick with what the feature pack has to deliver.
Before we add any code to our application, we need to add the resources that will contain the images to show. The images you use should be BMP with 32-bit depth. The ones below satisfy these criteria. Use the resource view to add the files, and after the properties tab, change their name as follows:
Now it remains to create the ribbon. Add a function in which we are going to handle the tasks considering the ribbon. I have chosen the name of InitRibbon ():
protected:
bool InitRibbon ();
Now create the ribbon in the OnCreate method of the mainframe and call the initialization process:
if (! m_wndRibbonBar.Create (this))
{
return -1; //Error in the creation of the ribbon
}
InitRibbon ();
I docked the toolbar manually to the down side of the application, so we can better see what we are doing. Now we set the image for the main ribbon button and add a tooltip text for it:
bool CMainFrame::InitRibbon ()
{
// Load the images and set the text for the main button
We can add menu points by first adding a main category. The main category will have a name and two image lists. The first contains the small icons (the ones you can see, for instance, in the quick access toolbar) and the second the images for the large icons (in the menu itself).
Adding menu points resembles adding buttons to the main panel. First specify the ID of the menu item, and then the text to show near it; finally, specify the index of the small and large icon inside the image list you specified. The examples underneath will make this clear:
The Quick access toolbar functionality is a built-in item for the ribbon. As soon as there are some menu points, you can customize them to add it there. You only need to specify the commands for the items to make this option possible.
As you can observe, these commands took over the behavior of the ones on the command bar. Therefore, they are grayed out when the option makes no sense and are activated once it is possible. Using the same system, we can easily add an exit menu item to the bottom with the following line:
pMainPanel->AddToBottom (
new CMFCRibbonMainPanelButton (ID_APP_EXIT,
"Out of here", 15));
Now all we need to add to make it look close to the Office style is the recent file list. For this, we need to perform some tasks beforehand. The first one is a lapse of the initial developer of the program. It failed to create the serialization system and instead came up with a custom function that handles all this. We need to call this from the serialization section. Open the xmltreeDoc.h and find the Serialize function. Extend it as follows:
if (ar.IsStoring())
{
}
else
{
CString temp;
LoadXML (ar.GetFile () ->GetFilePath (), temp);
}
Second, we need to add a file to the recent list whenever we open a new file. Open the xmltree.cpp file and find the OnFileOpen function at the end. As soon as the code snippet asks for the file, add this to the list with the function beneath:
//the call for the Path name
CString m_File1 = dlg.GetPathName ();
//Add these lines of code:
static_cast<CXmltreeApp*> (
AfxGetApp ())->AddToRecentFileList(m_File1);
Third, add to the beginning of the LoadXML (inside xmltreeDoc.cpp) method the following C++ code:
Although all this contributes to the effect created by using a ribbon, the central start remains the ribbon bar. In order to create one, first you need to understand its construction. The image below attempts to explain this:
The most important is the contextual tab with its sub-groups. We will try to transform the functions from the toolbar to this. First, we need to add a new tab to the ribbon:
We add a new category for which we specify its name and an image list for the small icons (I am going to use IDR_MAINFRAME) and the large icons (IDB_FILE_LARGE). These lists must contain the images for all the controls you intend to include in this tab. For example, the Home tab above should contain all the images for the paste, copy, left, right and so forth.
The groups you can find inside a category (tab) can be shown on the Quick Access Toolbar. For this reason, we need to assign to each of these a small icon. The easiest way to do this is to load inside a CMFCToolBarImages object an image from the resource. Afterward, you can extract the icons from this by specifying the index of the one desired. Add one of these variables to the Mainframe class. Then extend the initialization of the ribbon:
I already added the first group. Now we can populate with various pre-defined items with the usage of a single function: the Add:
View_As->Add (new CMFCRibbonButton (ID_VIEW_SMALLICON,
_T ("Small Icon"), 7));
View_As->Add (new CMFCRibbonButton (ID_VIEW_LARGEICON,
_T ("Large Icon"), 8));
View_As->Add (new CMFCRibbonButton (ID_VIEW_LIST,
_T ("View List"), 9));
View_As->Add (new CMFCRibbonButton (ID_VIEW_DETAILS,
_T ("Details"), 0, 10));
In the case of buttons, just specify the control ID of the button (taken from the toolbar or menu item), and specify the name you want to appear near it. Finally, you can choose a small icon from the small image list with a single integer number as a parameter, or add a large image as well if you specify two integers. The Ribbon will try to show the large icon if that is possible. Take a look:
Adding the group to the Quick Access is also possible. The controls will remain grayed out if using them is not possible. The ribbon controls will inherit the traits of the control in the case of the toolbar. You do not need to write any more code. Just add it to the ribbon and observe that it works!
We can also add check boxes. We will transform the view menu section to the ribbon to demonstrate this. This can be handy if you want to show or hide the Statusbar or the toolbar:
pPanelView->Add (new CMFCRibbonCheckBox (ID_VIEW_STATUS_BAR,
_T ("Status bar")));
pPanelView->Add (new CMFCRibbonCheckBox (
ID_VIEW_TOOLBAR, _T ("Toolbar")));
Following the same guidelines, we can add a window management section as well (as you can see from the image above, I already did so). We will first add a button to which we assign a large image. Afterward we will add sub items to this to create menu-like behavior.
// Add a panel to control the display of MDI windows
CMFCRibbonButton* pBtnWindows = new CMFCRibbonButton (0, _T ("Windowsnw"), -1, 1);
pBtnWindows->AddSubItem (new CMFCRibbonButton (ID_WINDOW_NEW, _T ("New Window"), -1, -1), -1);
pBtnWindows->AddSubItem (new CMFCRibbonButton (ID_WINDOW_CASCADE, _T ("Cascade"), -1, -1), -1);
pBtnWindows->AddSubItem (new CMFCRibbonButton (
ID_WINDOW_TILE_HORZ, _T ("Tile"), -1, -1), -1);
pPanelWindow->Add (pBtnWindows);
If you do not want to display any icon/image for an item, you can pass as an argument minus one. For reasons of completeness I also added a new help category. For this, I included a help link and an about button. The code is straightforward:
pPanelHelp->Add (new CMFCRibbonButton (ID_HELP_FINDER, _T ("Help Topics"), 12));
pPanelHelp->Add (new CMFCRibbonButton (ID_APP_ABOUT, _T (
"About XML Tree Viewer..."), 13));
If for some reason you failed to follow the coding part, here is my final version:
I would like to express my appreciation towards you for reading to the end this article. Please enter any questions you may have to the blog commenting section that you can find below or join our friendly site over at DevHardware or DevArticles and tell us your thoughts/problems there. I would also like to ask you to rate my article accordingly. This article was intended more to be a teaser to the world of the Ribbon. I plan to write more articles on this topic that are more detailed. Therefore, If you are interested, remember to check back from time to time. Live With Passion!