Click here to Skip to main content
16,016,229 members
Articles / Desktop Programming / MFC

Adding New Theme Variations to the MFC Ribbon (CMFCVisualManager)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (26 votes)
1 Nov 2017CPOL3 min read 36.3K   2.6K   21   7
Add new Ribbon themes to MFC application built using VS Feature Pack' classes
This article shows how to add new Ribbon themes to an MFC application built using the Visual Studio 'Feature Pack' (CMFCVisualManager) classes.

Introduction

This article presents a class derived from CMFCVisualManager which allows any number of colour variations to be used on the MFC Ribbon menu. Each variation can simply be added to your application's style menu and switched to via CMainFrame::OnApplicationLook(), just like the standard theme variations.

My MFC application already used the MFC Feature Pack classes and ribbon but I wanted it to have a more modern look as the original themes are beginning to look a bit dated. Rather than go through the pain of replacing the existing code with a paid-for updated ribbon (Codejock looks pretty good), I decided to see how far simply changing the colours on the existing themes would take me. Here are some samples of what's possible with the class I developed.

Examples of what's possible with this class

The article application (in the zip download) re-uses the standard 'RibbonGadgets' application from the Microsoft Visual Studio MFC Feature Pack samples and adds a 'Deviant Editor' additional tab. This additional tab lets you visually design your new theme. The button labeled 'Get Code' launches a window containing the specific code for the current theme, which you can copy / paste into your application's CMainFrame::OnApplicationLook().

Sample application

Clicking the 'Get Code' button launches a window containing the core C++ to render the current theme from the sample application:

Code view

Using the Code

The following instructions show how to implement the CMFCVisualManagerDeviant class in a new Visual Studio 2015 MFC project. Adding it to an existing project should be pretty similar.

First, create a new MFC application using the Visual Studio Application Wizard, making sure you select a 'Project style' of 'Office' on the 'Application Type' dialog. On the 'User Interface Features' dialog, ensure you choose the 'Use ribbon' option.

Now add a new menu entry to the ribbon's 'Style' menu in the resource editor. In the screenshot, we've used the ID ID_VIEW_APPLOOK_DEVIANT1.

Add new style to menu

Now, we need to capture the Style menu event in CMainFrame. On the assumption that you're going to want to add more than one new style, navigate to the BEGIN_MESSAGE_MAP section of your CMainFrame and add the following code inside the BEGIN_MESSAGE_MAP section. The *_RANGE macros capture the range of IDs from the first to the second.

C++
ON_COMMAND_RANGE(ID_VIEW_APPLOOK_DEVIANT1, ID_VIEW_APPLOOK_DEVIANT1, 
                 &CMainFrame::OnApplicationLook)
ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_APPLOOK_DEVIANT1, 
ID_VIEW_APPLOOK_DEVIANT1, &CMainFrame::OnUpdateApplicationLook)

In CMainFrame::OnApplicationLook(), make the following changes:

  1. In the code block starting switch (theApp.m_nAppLook), add a case statement for the new theme ID:, pasting in the code you copied from the 'Get Code' button option from the sample application. In the SetStyle() statement, choose the existing visual theme enumerator that looks best with your colour theme - for example, CMFCVisualManagerOffice2007::Office2007_Silver.
    C++
    case ID_VIEW_APPLOOK_DEVIANT1:
    {
                    CMFCVisualManagerOffice2007::SetStyle
                              (CMFCVisualManagerOffice2007::Office2007_Silver);
                    CMFCVisualManager::SetDefaultManager
                              (RUNTIME_CLASS(CMFCVisualManagerDeviant));
                    CMFCVisualManagerDeviant* pVisMan = 
                              (CMFCVisualManagerDeviant*)CMFCVisualManager::GetInstance();
                    if (pVisMan->GetRuntimeClass() == 
                               RUNTIME_CLASS(CMFCVisualManagerDeviant))
                    {
                        // Ribbon Bar properties
                        pVisMan->SetClrRibbonBarBackground(RGB(241, 241, 241));
                        pVisMan->SetClrRibbonBarTextPB(RGB(75, 75, 75));
                        pVisMan->SetClrRibbonBarTextHighlightedPB(RGB(0, 128, 0));
                        m_clrMenuBarBk = RGB(241, 241, 241);
    
                        // Ribbon Category Properties
                        pVisMan->SetClrRibbonCategoryBkTop(RGB(255, 255, 255));
                        pVisMan->SetClrRibbonCategoryBkBottom(RGB(255, 255, 255));
    
                        // Ribbon Panel Properties
                        pVisMan->SetClrRibbonPanelBkTop(RGB(255, 255, 255));
                        pVisMan->SetClrRibbonPanelBkBottom(RGB(255, 255, 255));
                        pVisMan->SetClrRibbonPanelCaptionBk(RGB(241, 241, 241));
                        pVisMan->SetClrRibbonPanelCaptionTextPB(RGB(68, 68, 68));
                        pVisMan->SetClrRibbonPanelCaptionTextHighlightedPB(RGB(77, 0, 38));
                        pVisMan->SetClrRibbonPanelTextPB(RGB(60, 60, 60));
    
                        // Ribbon Panel outline colour
                        pVisMan->SetClrRibbonPanelOutline(RGB(210, 210, 210));
                    }
                }
                break;
  2. Locate the following line of code in CMainFrame::OnApplicationLook() which should be the third from last statement within the switch (theApp.m_nAppLook) block.
    C++
    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
    
    Replace it with the following:
    C++
    if(theApp.m_nAppLook >= ID_VIEW_APPLOOK_OFF_2007_BLUE && 
                 theApp.m_nAppLook <= ID_VIEW_APPLOOK_OFF_2007_AQUA)
       CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
  3. Finally, disable redraw at the start of CMainFrame::OnApplicationLook() with SetRedraw(FALSE) and re-enable at the end with SetRedraw(TRUE) in order to avoid screen flicker.
  4. Here is the full CMainFrame::OnApplicationLook() code. The additions and changes are commented starting // **

    C++
    void CMainFrame::OnApplicationLook(UINT id)
    {
       CWaitCursor wait;
    
       theApp.m_nAppLook = id;
    
       // ** Disable redrawing
       SetRedraw(FALSE);
    
       switch (theApp.m_nAppLook)
       {
       case ID_VIEW_APPLOOK_WIN_2000:
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManager));
          m_wndRibbonBar.SetWindows7Look(FALSE);
          break;
    
       case ID_VIEW_APPLOOK_OFF_XP:
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOfficeXP));
          m_wndRibbonBar.SetWindows7Look(FALSE);
          break;
    
       case ID_VIEW_APPLOOK_WIN_XP:
          CMFCVisualManagerWindows::m_b3DTabsXPTheme = TRUE;
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
          m_wndRibbonBar.SetWindows7Look(FALSE);
          break;
    
       case ID_VIEW_APPLOOK_OFF_2003:
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2003));
          CDockingManager::SetDockingMode(DT_SMART);
          m_wndRibbonBar.SetWindows7Look(FALSE);
          break;
    
       case ID_VIEW_APPLOOK_VS_2005:
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
          CDockingManager::SetDockingMode(DT_SMART);
          m_wndRibbonBar.SetWindows7Look(FALSE);
          break;
    
       case ID_VIEW_APPLOOK_VS_2008:
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2008));
          CDockingManager::SetDockingMode(DT_SMART);
          m_wndRibbonBar.SetWindows7Look(FALSE);
          break;
    
       case ID_VIEW_APPLOOK_WINDOWS_7:
          CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));
          CDockingManager::SetDockingMode(DT_SMART);
          m_wndRibbonBar.SetWindows7Look(TRUE);
          break;
       default:
          switch (theApp.m_nAppLook)
          {
          case ID_VIEW_APPLOOK_OFF_2007_BLUE:
             CMFCVisualManagerOffice2007::SetStyle
                  (CMFCVisualManagerOffice2007::Office2007_LunaBlue);
             break;
    
          case ID_VIEW_APPLOOK_OFF_2007_BLACK:
             CMFCVisualManagerOffice2007::SetStyle
                 (CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
             break;
    
          case ID_VIEW_APPLOOK_OFF_2007_SILVER:
             CMFCVisualManagerOffice2007::SetStyle
                      (CMFCVisualManagerOffice2007::Office2007_Silver);
             break;
    
          case ID_VIEW_APPLOOK_OFF_2007_AQUA:
             CMFCVisualManagerOffice2007::SetStyle
                       (CMFCVisualManagerOffice2007::Office2007_Aqua);
             break;
          case ID_VIEW_APPLOOK_DEVIANT1:  // ** Use the ID you added to the 'Style' menu 
                                          // in the Ribbon editor
             {
                CMFCVisualManagerOffice2007::SetStyle
                          (CMFCVisualManagerOffice2007::Office2007_Silver);
                CMFCVisualManager::SetDefaultManager
                          (RUNTIME_CLASS(CMFCVisualManagerDeviant));
                CMFCVisualManagerDeviant* pVisMan = 
                     (CMFCVisualManagerDeviant*)CMFCVisualManager::GetInstance();
                if (pVisMan->GetRuntimeClass() == RUNTIME_CLASS(CMFCVisualManagerDeviant))
                {
                   // Ribbon Bar properties
                   pVisMan->SetClrRibbonBarBackground(RGB(0, 0, 128));
                   pVisMan->SetClrRibbonBarTextPB(RGB(255, 255, 255));
                   pVisMan->SetClrRibbonBarTextHighlightedPB(RGB(0, 0, 0));
    
                   // Ribbon Category Properties
                   pVisMan->SetClrRibbonCategoryBkTop(RGB(0, 0, 128));
                   pVisMan->SetClrRibbonCategoryBkBottom(RGB(166, 202, 240));
    
                   // Ribbon Panel Properties
                   pVisMan->SetClrRibbonPanelBkTop(RGB(166, 202, 240));
                   pVisMan->SetClrRibbonPanelBkBottom(RGB(255, 255, 255));
                   pVisMan->SetClrRibbonPanelCaptionBk(RGB(166, 202, 240));
                   pVisMan->SetClrRibbonPanelCaptionTextPB(RGB(0, 0, 128));
                   pVisMan->SetClrRibbonPanelCaptionTextHighlightedPB(RGB(255, 255, 255));
                   pVisMan->SetClrRibbonPanelTextPB(RGB(0, 0, 128));
    
                   // Ribbon Panel outline colour
                   pVisMan->SetClrRibbonPanelOutline(RGB(255, 255, 255));
                }
             }
             break;
          }
    
          // ** Set standard visual manager if it's a standard theme
          if(theApp.m_nAppLook >= ID_VIEW_APPLOOK_OFF_2007_BLUE && 
          		theApp.m_nAppLook <= ID_VIEW_APPLOOK_OFF_2007_AQUA)
             CMFCVisualManager::SetDefaultManager
                       (RUNTIME_CLASS(CMFCVisualManagerOffice2007));
    
    
          CDockingManager::SetDockingMode(DT_SMART);
          m_wndRibbonBar.SetWindows7Look(FALSE);
       }
    
       // ** Re-enable redraw
       SetRedraw(TRUE);
       RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | 
                                 RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
    
       theApp.WriteInt(_T("ApplicationLook"), theApp.m_nAppLook);
    }

You can add any number of additional themes by iterating the above process.

Points of Interest

I'm not going to explain how the CMFCVisualManagerDeviant class works - why be different to Microsoft, haha, the code is there for you to read! The goal was to provide a simple, add-in class that can be easily plugged into any new or existing application which uses the Feature Pack ribbon. It got to its current state with many hours of code browsing and experimentation.

However, there are two things that have eluded me to date, and I'd welcome anyone contributing a solution.

  1. I haven't cracked how to change the menu text colours for the Style menu:

    Style menu text issue

  2. I can't change the background colour of the 'orb' menu:

    Orb menu text colour

These snags are only problematic on some combinations of colours, but it would be fantastic to resolve them.

I will integrate any changes that resolve these issues or improve this class upon receipt.

History

  • 31st October, 2017 - Initial article submitted

License

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


Written By
CEO Data Perceptions
United Kingdom United Kingdom
Software designer and developer of Prophecy, a multi-user solution for sales forecasting and the Software Update Wizard, an automatic updates component that lets software developers add automatic updates to their Windows applications with a single line of code and which supports automatic updates, even where the logged in user does not have (write) rights to Program Files etc. folders.

I started working life as full time sales forecaster in the CPG sector. Transitioned to IT as I had an interest in software development and felt combining this with my previous business experience would be good.

After many years working for a company I developed Prophecy as a spare-time project and became self-employed in 1998, with Prophecy and the Software Update Wizard as my sole sources of income. It's been an interesting and challenging ride!

Comments and Discussions

 
Praisevery well. Pin
吴克亮1-Aug-19 16:46
吴克亮1-Aug-19 16:46 
AnswerSolution Points of Interest Pin
CiccioMnz14-Dec-18 5:13
CiccioMnz14-Dec-18 5:13 
GeneralRe: Solution Points of Interest Pin
LebrunThierry23-Sep-22 2:35
LebrunThierry23-Sep-22 2:35 
QuestionMain title bar text not visible when window maximized Pin
rfl.souza5-Jun-18 9:26
rfl.souza5-Jun-18 9:26 
Will you keep this code in some repository? I was going to make a correction of the MFC.

Take advantage and add in your class the fix.

MFCVisualManagerDeviant.h:
C++
	//FIX Main title bar text when window maximized
BOOL DrawTextOnGlass(CDC* pDC, CString strText, CRect rect, DWORD dwFlags, int nGlowSize = 0, COLORREF clrText = (COLORREF)-1) override;

MFCVisualManagerDeviant.cpp:
C++
BOOL CMFCVisualManagerDeviant::DrawTextOnGlass(CDC * pDC, CString strText, CRect rect, DWORD dwFlags, int nGlowSize, COLORREF clrText)
{
	return CMFCVisualManagerOffice2007::DrawTextOnGlass(pDC, strText, rect, dwFlags, nGlowSize, RGB(0, 0, 0));
}


Reference: Main title bar text not visible when window maximized - Microsoft Community[^]
Rafael

Questiondo you know how to customize theme images? Pin
rfl.souza28-May-18 7:38
rfl.souza28-May-18 7:38 
QuestionOffice themes Pin
Member 1053717-Jan-18 11:53
Member 1053717-Jan-18 11:53 
AnswerRe: Office themes Pin
peterboulton16-Feb-18 4:09
professionalpeterboulton16-Feb-18 4:09 

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

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