Relook your Old and New Native Applications with a Ribbon UI under Vista or Windows 7 (WTL)
Introduction
Windows 7 introduces a new Ribbon control, a system update makes it available to Vista and Windows Server 2008 platforms.
This article concentrates on a C++ application programer's point of view in the process of adapting existing or new applications to give the user a reversible choice between a Ribbon or traditional UI, using atlribbon.h and WTL 8.
-
Preview presents the dual UI Ribbon enabled MTPad WTL sample.
-
First Experience creates a simple dual UI application from the WTL AppWizard code without adding any resource to the AppWizard application.
-
Ribbon UI Implementation Guide describes with examples the implementation of a Ribbon UI.
-
Relooking MTPad with a Ribbon UI shows the adaptation of an existing application.
References
The main documentation about the Windows 7 Ribbon is the MSDN Windows Ribbon Framework section.
You can find in CodeProject Michael Chourdakis's article : Windows 7 Ribbon: The Time Has Come, Your Win32 Application Will Change, and in Arik Poznanski's Blog detailed descriptions of the Ribbon features, and Windows Ribbon for WinForms to operate it in C# applications.
Prerequisites
To follow this article you need to have correctly installed on your computer:
-
Visual Studio or VCExpress 2008 with all service packs or Visual Studio 2010 Beta2.
-
The Windows 7 platform SDK: you need the uicc tool which is not part of Visual Studio 2010 Beta2 distribution.
-
With VCExpress you need ATL 3 that can be found in the Windows® Server 2003 SP1 Platform SDK or ATL 7.1 as indicated in this post.
Obviously you should test on an updated Vista or a Windows 7 platform, you can compile and run everything under Vista, Windows 7 or XP.
Preview
Download MTPad7Exe.zip and run MTPad.exe.
On an updated Vista or a Windows 7 platform MTPad opens with a Ribbon UI.
Open some text files, check the font selection preview feature, try the Print Preview mode, use the recent files in the Application Menu, open some new windows.
Uncheck the Ribbon checkbox to switch to traditional UI, use the View menu Ribbon entry to switch back to ribbon UI in Edit or Preview mode.
Change the layout settings using the built-in dropdown at right of the QAT (Quick Access Toolbar), then switch back and forth to traditional UI and notice that when you switch back to Ribbon UI the ribbon layout settings are persisted.
Close the last window in traditional UI and reopen MTPad. It reopens traditional.
First Experience
Using atlribbon.h, in some minutes you can build a dual (ribbon and traditional) user selectable UI on top of a traditional UI WTL application.
This first experience performs the necessary steps, with many execution details, as they apply to any Ribbon UI application.
Step 0: Create a WTL Application with minimal functionality
If you use Visual Studio 2010 Beta2 or for some reason have not installed the WTL AppWizard, download FirstRibbon.zip , unzip it and open FirstRibbon.vcproj.
Otherwise with the WTL AppWizard, create a FirstRibbon WTL application with SDI and no cpp...
... default User Interface Features and Rich Edit view window.
To handle the Edit commands add CRichEditCommands
inheritance and message map chaining to CFirstRibbonView
...
// FirstRibbonView.h : interface of the CFirstRibbonView class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
class CFirstRibbonView :
public CWindowImpl<CFirstRibbonView, CRichEditCtrl>, // 0
public CRichEditCommands<CFirstRibbonView> // 0
{
public:
DECLARE_WND_SUPERCLASS(NULL, CRichEditCtrl::GetWndClassName())
BOOL PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
BEGIN_MSG_MAP(CFirstRibbonView)
CHAIN_MSG_MAP_ALT(CRichEditCommands<CFirstRibbonView>, 1) // 0
END_MSG_MAP()
};
… and chain the CMainFrame
commands to CFirstRibbonView
:
// MainFrm.h : interface of the CMainFrame class
// ...
BEGIN_MSG_MAP(CMainFrame)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
CHAIN_COMMANDS_MEMBER(m_view) // 0
CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
CHAIN_MSG_MAP(CFrameWindowImpl<CMainFrame>)
END_MSG_MAP()
Compile (any compilation error here means that your development environment is not correctly set up), run and check the edit functions with the toolbar buttons or the Edit menu.
Step 1: Adapt the C++ code to host a Ribbon UI
Change the constants in stdafx.h to access the SDK Windows 7 features.
// stdafx.h : include file for standard system include files,
//...
// Change these values to use different versions
#define WINVER 0x0601 // 1
#define _WIN32_WINNT 0x0601 // 1
#define _WIN32_IE 0x0700 // 1
#define _RICHEDIT_VER 0x0200
Download atlribbon.zip, extract atlribbon.h to your <FirstRibbon> directory, and include it in FirstRibbon.cpp.
// FirstRibbon.cpp : main source file for FirstRibbon.exe
//
#include "stdafx.h"
#include <atlframe.h>
#include <atlctrls.h>
#include <atldlgs.h>
#include <atlctrlw.h>
#include "atlribbon.h" // 1
#include "resource.h"
Derive CMainFrame
from WTL::CRibbonFrameWindowImpl
; as CRibbonFrameWindowImpl
derives from WTL::CRibbonUpdateUI
, remove the CUpdateUI
parent in the class definition and the message map and chain only CRibbonFrameWindowImpl<CMainFrame>
in the message map.
// MainFrm.h : interface of the CMainFrame class
// ...
class CMainFrame :
public CRibbonFrameWindowImpl<CMainFrame>, // 1
public CMessageFilter, public CIdleHandler
// ...
BEGIN_MSG_MAP(CMainFrame)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)
COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)
COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
CHAIN_COMMANDS_MEMBER(m_view) // 0
CHAIN_MSG_MAP(CRibbonFrameWindowImpl<CMainFrame>) // 1
END_MSG_MAP()
To run on pre-Vista or non updated Vista platforms, in Project->FirstRibbon Properties->Linker->Input set propsys.dll and dwmapi.dll as Delay Loaded.
Compile to check that the step is completed.
Step 2: Create a ribbon ressource and embed it in the application
Add to your project a new xml file (for VCExpress a new C++ header file), name it FirstRibbonRibbon.xml and paste what follows into it:
<!-- FirstRibbonRibbon.xml -->
<Application xmlns="http://schemas.microsoft.com/windows/2009/Ribbon">
<Application.Commands>
<!-- FirstTab.rc Menu Commands-->
<Command Name="wtl_FILE_NEW" Symbol="ID_FILE_NEW" Id="0xE100"/>
<Command Name="wtl_FILE_OPEN" Symbol="ID_FILE_OPEN" Id="0xE101"/>
<Command Name="wtl_FILE_SAVE" Symbol="ID_FILE_SAVE" Id="0xE103"/>
<Command Name="wtl_FILE_SAVE_AS" Symbol="ID_FILE_SAVE_AS" Id="0xE104"/>
<Command Name="wtl_FILE_PRINT" Symbol="ID_FILE_PRINT" Id="0xE107"/>
<Command Name="wtl_FILE_PRINT_PREVIEW" Symbol="ID_FILE_PRINT_PREVIEW" Id="0xE109"/>
<Command Name="wtl_FILE_PRINT_SETUP" Symbol="ID_FILE_PRINT_SETUP" Id="0xE106"/>
<Command Name="wtl_APP_EXIT" Symbol="ID_APP_EXIT" Id="0xE141"/>
<Command Name="wtl_EDIT_CUT" Symbol="ID_EDIT_CUT" Id="0xE123"/>
<Command Name="wtl_EDIT_COPY" Symbol="ID_EDIT_COPY" Id="0xE122"/>
<Command Name="wtl_EDIT_PASTE" Symbol="ID_EDIT_PASTE" Id="0xE125"/>
<Command Name="wtl_VIEW_TOOLBAR" Symbol="ID_VIEW_TOOLBAR" Id="0xE800"/>
<Command Name="wtl_VIEW_STATUS_BAR" Symbol="ID_VIEW_STATUS_BAR" Id="0xE801"/>
<Command Name="wtl_VIEW_RIBBON" Symbol="ID_VIEW_RIBBON" Id="0xE804"/>
<Command Name="wtl_APP_ABOUT" Symbol="ID_APP_ABOUT" Id="0xE140"/>
<!-- Tabs -->
<Command Name="TabHome" Symbol="ID_TAB_HOME"
LabelTitle="Home" />
<!-- Groups -->
<Command Name="GroupClipboard" Symbol="ID_GROUP_CLIPBOARD"
LabelTitle="Clipboard" />
<Command Name="GroupView" Symbol="ID_GROUP_VIEW"
LabelTitle="View" />
<!-- App Menu, MRU list, Help button and Quick Access Toolbar -->
<Command Name="AppMenu" Symbol="ID_RIBBON_APP_MENU"/>
<Command Name="SaveMore" Symbol="ID_SAVEMORE"/>
<Command Name="PrintMore" Symbol="ID_PRINTMORE"/>
<Command Name="QAT" Symbol="ID_RIBBON_QAT"/>
</Application.Commands>
<Application.Views>
<Ribbon>
<!-- Application Menu -->
<Ribbon.ApplicationMenu >
<ApplicationMenu CommandName="AppMenu" >
<MenuGroup Class="StandardItems" >
<Button CommandName="wtl_FILE_NEW"/>
<Button CommandName="wtl_FILE_OPEN"/>
<!-- Saving SplitButton -->
<SplitButton CommandName="SaveMore">
<SplitButton.ButtonItem>
<Button CommandName="wtl_FILE_SAVE" />
</SplitButton.ButtonItem>
<SplitButton.MenuGroups>
<MenuGroup Class="StandardItems">
<Button CommandName="wtl_FILE_SAVE" />
<Button CommandName="wtl_FILE_SAVE_AS" />
</MenuGroup>
</SplitButton.MenuGroups>
</SplitButton>
<!-- Printing SplitButton -->
<SplitButton CommandName="PrintMore">
<SplitButton.ButtonItem>
<Button CommandName="wtl_FILE_PRINT"/>
</SplitButton.ButtonItem>
<SplitButton.MenuGroups>
<MenuGroup Class="StandardItems">
<Button CommandName="wtl_FILE_PRINT" />
<Button CommandName="wtl_FILE_PRINT_PREVIEW"/>
<Button CommandName="wtl_FILE_PRINT_SETUP"/>
</MenuGroup>
</SplitButton.MenuGroups>
</SplitButton>
</MenuGroup>
<MenuGroup >
<Button CommandName="wtl_APP_EXIT"/>
</MenuGroup>
</ApplicationMenu>
</Ribbon.ApplicationMenu >
<!-- Help button -->
<Ribbon.HelpButton>
<HelpButton CommandName="wtl_APP_ABOUT" />
</Ribbon.HelpButton>
<!-- QAT (Quick Access Toolbar) -->
<Ribbon.QuickAccessToolbar>
<QuickAccessToolbar CommandName="QAT">
<QuickAccessToolbar.ApplicationDefaults>
<Button CommandName="wtl_FILE_NEW"/>
<Button CommandName="wtl_FILE_OPEN"/>
<Button CommandName="wtl_FILE_SAVE"/>
<Button CommandName="wtl_FILE_PRINT"/>
</QuickAccessToolbar.ApplicationDefaults>
</QuickAccessToolbar>
</Ribbon.QuickAccessToolbar>
<Ribbon.Tabs>
<Tab CommandName="TabHome">
<Tab.ScalingPolicy>
<ScalingPolicy>
<ScalingPolicy.IdealSizes>
<Scale Group="GroupClipboard" Size="Medium"/>
<Scale Group="GroupView" Size="Large"/>
</ScalingPolicy.IdealSizes>
</ScalingPolicy>
</Tab.ScalingPolicy>
<Group CommandName="GroupClipboard" SizeDefinition="