WTL-Ribbon
1.在WTL项目中添加Ribbon的布局定义文件:RibbonMarkup.xml
<Application xmlns="http://schemas.microsoft.com/windows/2009/Ribbon"><Application.Commands><Command Name="TabHome" Symbol="IDC_TabHome" Id="30000" LabelTitle="Home"/><Command Name="GroupMain" Symbol="IDC_GroupMain" Id="30001" LabelTitle="Main"/><Command Name="Toggle" Symbol="IDC_TOGGLE" Id="30002" LabelTitle="Toggle"><Command.TooltipTitle>Toggle button</Command.TooltipTitle><Command.TooltipDescription>Click on Toggle SayHello Button.</Command.TooltipDescription><Command.LargeImages><Image Source="Button_Image.bmp"/></Command.LargeImages></Command><Command Name="SayHello" Symbol="IDC_SAY_HELLO" Id="30003" LabelTitle="Say hello"><Command.TooltipTitle>SayHello button</Command.TooltipTitle><Command.TooltipDescription>Say hello to me!</Command.TooltipDescription><Command.LargeImages><Image Source="Button_Image.bmp"/></Command.LargeImages></Command></Application.Commands><Application.Views><Ribbon><Ribbon.Tabs><Tab CommandName="TabHome"><Group CommandName="GroupMain" SizeDefinition="TwoButtons"><ToggleButton CommandName="Toggle"/><Button CommandName="SayHello"/></Group></Tab></Ribbon.Tabs></Ribbon></Application.Views></Application>
2.选中RibbonMarkup.xml,右键点击Properties,在Property Pages对话框中修改属性:
Command Line : uicc.exe RibbonMarkup.xml RibbonMarkup.bml /header:RibbonRes.h /res:RibbonRes.rc
Outputs: RibbonMarkup.bml;RibbonRes.rc;RibbonRes.h
3.编译项目,已生成资源文件和符号定义头文件
4.Ribbon的实现:
#pragma once#include <atlbase.h>#include <atlcom.h>#include <InitGuid.h>#include <UIRibbon.h>#include <UIRibbonPropertyHelpers.h>#pragma comment(lib,"propsys.lib")#include "RibbonRes.h"CComPtr<IUIApplication> g_spIUIApplication;CComPtr<IUIFramework> g_spIUIFramework;enum{WM_USER_RIBBON_RESIZE = WM_USER+1,WM_USER_RIBBON_COMMAND};////User defined message crack//// void OnRibbonResize(UINT height)#define MSG_WM_USER_RIBBONRESIZE(func) \if (uMsg == WM_USER_RIBBON_RESIZE) \{ \SetMsgHandled(TRUE); \func((UINT)wParam); \lResult = 0; \if(IsMsgHandled()) \return TRUE; \}// void OnRibbonCommand(UINT cmdID)#define MSG_WM_USER_COMMAND(func) \if (uMsg == WM_USER_RIBBON_COMMAND) \{ \SetMsgHandled(TRUE); \func((UINT)wParam); \lResult = 0; \if(IsMsgHandled()) \return TRUE; \}[uuid("6760F7D7-2B58-481E-BB35-D701B8C9576E")]__interface IRibbonNotifyWindow : public IUnknown{HRESULT __stdcall SetNotifyWindow(HWND hNotifyWindow);};class CRibbonApp :public CComObjectRootEx<CComMultiThreadModel>,public CComCoClass<CRibbonApp>,public IRibbonNotifyWindow,public IUIApplication,public IUICommandHandler{public:BEGIN_COM_MAP(CRibbonApp)COM_INTERFACE_ENTRY(IUIApplication)COM_INTERFACE_ENTRY(IUICommandHandler)COM_INTERFACE_ENTRY(IRibbonNotifyWindow)END_COM_MAP()////IRibbonNotifyWindow methods//STDMETHOD(SetNotifyWindow)(HWND hNotifyWindow){m_NotifyWindow = hNotifyWindow;return S_OK;}////IUIApplication methods//STDMETHOD(OnViewChanged)(UINT32 viewId,UI_VIEWTYPE typeID,__in IUnknown *pView,UI_VIEWVERB verb,INT32 /*uReasonCode*/){HRESULT hr = E_NOTIMPL;if (typeID == UI_VIEWTYPE_RIBBON){switch(verb){case UI_VIEWVERB_CREATE:hr = S_OK;break;case UI_VIEWVERB_SIZE:{CComPtr<IUIRibbon> spUIRibbon;hr = pView->QueryInterface(IID_PPV_ARGS(&spUIRibbon));CHECKHR(hr);UINT32 height;spUIRibbon->GetHeight(&height);m_NotifyWindow.PostMessage(WM_USER_RIBBON_RESIZE,height);}break;case UI_VIEWVERB_DESTROY:hr = S_OK;break;}}return hr;}STDMETHOD(OnCreateUICommand)(UINT32 nCmdID,UI_COMMANDTYPE typeID,__out IUICommandHandler** ppCommandHandler){if ((nCmdID==IDC_TOGGLE) || (nCmdID==IDC_SAY_HELLO)){return QueryInterface(IID_PPV_ARGS(ppCommandHandler));}return E_NOTIMPL;}STDMETHOD(OnDestroyUICommand)(UINT32 commandId,UI_COMMANDTYPE typeID,__in IUICommandHandler* pCommandHandler){return E_NOTIMPL;}////IUICommandHandler methods//STDMETHODIMP Execute(UINT nCmdID,UI_EXECUTIONVERB verb,__in_opt const PROPERTYKEY* key,__in_opt const PROPVARIANT* pPropvarValue,__in_opt IUISimplePropertySet* pCommandExecutionProperties){HRESULT hr = S_OK;switch (verb){case UI_EXECUTIONVERB_EXECUTE:if (nCmdID == IDC_SAY_HELLO){m_NotifyWindow.PostMessage(WM_USER_RIBBON_COMMAND,IDC_SAY_HELLO);}else if (nCmdID == IDC_TOGGLE){PROPVARIANT var, varNew;hr = g_spIUIFramework->GetUICommandProperty(IDC_SAY_HELLO, UI_PKEY_Enabled, &var);CHECKHR(hr);hr = PropVariantToBoolean(var, &m_IsSayHelloEnabled);CHECKHR(hr);m_IsSayHelloEnabled = !m_IsSayHelloEnabled;hr = UIInitPropertyFromBoolean(UI_PKEY_Enabled, m_IsSayHelloEnabled, &varNew);CHECKHR(hr);hr = g_spIUIFramework->SetUICommandProperty(IDC_SAY_HELLO, UI_PKEY_Enabled, varNew);CHECKHR(hr);hr = g_spIUIFramework->InvalidateUICommand(IDC_TOGGLE, UI_INVALIDATIONS_PROPERTY, &UI_PKEY_Label);CHECKHR(hr);}break;}return hr;}STDMETHODIMP UpdateProperty(UINT nCmdID,__in REFPROPERTYKEY key,__in_opt const PROPVARIANT* ppropvarCurrentValue,__out PROPVARIANT* pPropvarNewValue){HRESULT hr = E_FAIL;if (key == UI_PKEY_Label){// Update the Label of ToggleButton controlif (nCmdID == IDC_TOGGLE){if (m_IsSayHelloEnabled){hr = UIInitPropertyFromString(UI_PKEY_Label,L"Disable", pPropvarNewValue);}else{hr = UIInitPropertyFromString(UI_PKEY_Label,L"Enable", pPropvarNewValue);}}}return hr;}private:CWindow m_NotifyWindow;BOOL m_IsSayHelloEnabled;};//Create and initialize ribbonHRESULT CreateRibbon(HWND hMainWnd){ATLASSERT(::IsWindow(hMainWnd));HRESULT hr = CRibbonApp::CreateInstance(&g_spIUIApplication);CHECKHR(hr);CComPtr<IRibbonNotifyWindow> spINotifyWindow;g_spIUIApplication.QueryInterface(&spINotifyWindow);ATLASSERT(spINotifyWindow != NULL);spINotifyWindow->SetNotifyWindow(hMainWnd);hr = g_spIUIFramework.CoCreateInstance(CLSID_UIRibbonFramework);CHECKHR(hr);hr = g_spIUIFramework->Initialize(hMainWnd, g_spIUIApplication);CHECKHR(hr);hr = g_spIUIFramework->LoadUI(::GetModuleHandle(NULL),_T("APPLICATION_RIBBON"));CHECKHR(hr);return hr;}//Destroy ribbonvoid DestroyRibbon(){g_spIUIFramework->Destroy();g_spIUIFramework = NULL;g_spIUIApplication = NULL;}//Get the height of ribbon controlUINT32 GetRibbonHeight(){ATLASSERT(g_spIUIFramework != NULL);CComPtr<IUIRibbon> spIUIRibbon;g_spIUIFramework->GetView(0,IID_PPV_ARGS(&spIUIRibbon));ATLASSERT(spIUIRibbon);UINT32 height;spIUIRibbon->GetHeight(&height);return height;}
5.在主窗口中使用Ribbon:
#pragma once#include "MyView.h"#include "Ribbon.h"typedef CWinTraits<WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN> CMyWindowTraits;class CMyWindow :public CWindowImpl<CMyWindow, CWindow, CMyWindowTraits>{public:CMyWindow(){CWndClassInfo& wci = GetWndClassInfo();if (!wci.m_atom){wci.m_wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);}}public:DECLARE_WND_CLASS(_T("My WTL main window"))BEGIN_MSG_MAP_EX(CMyWindow)MSG_WM_CREATE(OnCreate)MSG_WM_DESTROY(OnDestroy)MSG_WM_SIZE(OnSize)//Ribbon messageMSG_WM_USER_RIBBONRESIZE(OnRibbonResize)MSG_WM_USER_COMMAND(OnRibbonCommand)END_MSG_MAP()int OnCreate(LPCREATESTRUCT /*lpCreateStruct*/){//Create and initialize ribbonHRESULT hr = CreateRibbon(m_hWnd);CHECKHR(hr);//Create view windowCRect rc;GetClientRect(&rc);rc.top += GetRibbonHeight();m_View.Create(m_hWnd,rc,NULL,WS_CHILD|WS_VISIBLE);return 0;}void OnSize(UINT /*nType*/, CSize /*size*/){if (m_View.m_hWnd){CRect rc;GetClientRect(&rc);rc.top += GetRibbonHeight();m_View.SetWindowPos(m_hWnd,&rc,SWP_NOZORDER | SWP_NOACTIVATE);}}void OnRibbonResize(UINT height){CRect rc;GetClientRect(&rc);rc.top += height;m_View.SetWindowPos(m_hWnd,&rc,SWP_NOZORDER | SWP_NOACTIVATE);}void OnRibbonCommand(UINT cmdID){if (cmdID == IDC_SAY_HELLO){MessageBox(_T("MyButton button is clicked!"),_T("WTL ribbon message"));}}void OnDestroy(){//Destroy ribbonDestroyRibbon();PostQuitMessage(0);}private:CMyView m_View;};