Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Adding New Theme Variations to the MFC Ribbon (CMFCVisualManager)

5.00/5 (26 votes)
1 Nov 2017CPOL3 min read 36.4K   2.6K  
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)