Walkthrough: Updating the MFC Scribble Application (Part 2)

In Part 1 of this walkthrough we added an Office Fluent Ribbon to the classic Scribble application. In Part 2 of this walkthrough we add ribbon panels and controls to perform tasks that were previously performed by using the menu bar.

Prerequisites

SCRIBBLE Sample: MFC MDI Drawing Application

Sections

Part 2 of this walkthrough has the following sections:

  • Adding New Panels to the Ribbon

  • Adding a Help Panel to the Ribbon

  • Adding a Pen Panel to the Ribbon

  • Adding a Color Button to the Ribbon

  • Adding a Color Member to the Document Class

  • Initializing Pens and Saving Preferences

Adding New Panels to the Ribbon

In this step we add two panels. First, add a View panel that contains two check boxes that control the visibility of the toolbar and the status bar. Second, add a Window panel that contains a vertically oriented split button that controls the creation and arrangement of MDI windows.

To add a View panel and Window panel to the ribbon bar

  1. Add the following code to the CMainFrame::OnCreate method, immediately after the Edit panel code that you created in Part 1.

    // Add a panel to control the visibility of tool bars
    CMFCRibbonPanel* pPanelView = pCategory->AddPanel(
    // Set panel name
       _T("View"),
    // Set panel icon
       m_PanelImages.ExtractIcon(0));  
    // Add panel buttons for Toolbar and Status Bar
    pPanelView->Add(new CMFCRibbonCheckBox(
       ID_VIEW_TOOLBAR, _T("Toolbar")));
    pPanelView->Add(new CMFCRibbonCheckBox(
       ID_VIEW_STATUS_BAR, _T("Status Bar")));
    
  2. Immediately after the code that creates the View panel, add the following code to create a new panel named Window, which has a split button. When a user clicks the split button, a pop-up menu displays three menu items that were defined in Scribble 1.0.

    // Add a panel to control the display of MDI windows
    CMFCRibbonPanel* pPanelWindow = pCategory->AddPanel( _T("Window"), m_PanelImages.ExtractIcon(0));
    CMFCRibbonButton* pBtnWindows = new CMFCRibbonButton( 0, _T("Windows\nw"), -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);
    
  3. Save the changes and then build and run the application. The View and Window panels should appear. Click the buttons to confirm that they function correctly.

[go to top]

Adding a Help Panel to the Ribbon

Next, we assign two menu items defined in Scribble 1.0 to ribbon buttons named Help Topics and About Scribble…. We add the buttons to a new panel named Help.

To add a Help panel

  1. Add the following code to CMainFrame::OnCreate, immediately after the code for the Window panel that you added in the previous step.

    // Create a new panel with the name "Help"
    CMFCRibbonPanel* pPanelHelp = pCategory->AddPanel(
       _T("Help"),           
    m_PanelImages.ExtractIcon(0)); 
    pPanelHelp->Add(new CMFCRibbonButton(ID_HELP_FINDER, _T("Help Topics")));
    pPanelHelp->Add(new CMFCRibbonButton(ID_APP_ABOUT, _T(
       "About Scribble...")));
    
  2. Save the changes and then build and run the application. A Help panel that contains two ribbon buttons should appear.

    Important noteImportant Note:

    When you click the Help Topics button, the Scribble application opens a compressed HTML (.chm) help file named your_project_name.chm. Consequently, if your project is not named Scribble, you must rename the help file to your project name.

[go to top]

Adding a Pen Panel to the Ribbon

Next, we add a panel to display buttons that control the thickness and the color of the pen. This panel contains a check box that toggles between thick and thin pens. Its functionality resembles that of the Thick Line menu item in Scribble 1.0.

The original Scribble application lets the user select pen widths from a dialog box that appears when a user selects Pen Widths from the menu. Because we have ample room on our ribbon bar for new controls, we replace the dialog box with two combo boxes on the ribbon. One combo box adjusts the width of the thin pen and the other combo box adjusts the width of the thick pen.

To add a Pen panel and combo boxes to the ribbon

  1. Add the following code to the CMainFrame::OnCreate method, immediately after the code for the Edit panel that we created in Part 1.

    // Create a new panel for the pen-related buttons
    CMFCRibbonPanel* pPanelPen = pCategory->AddPanel(
    // Panel name
       _T("Pen"), 
    // Panel icon
       m_PanelImages.ExtractIcon(0));
    pPanelPen->Add(new CMFCRibbonCheckBox(
       ID_PEN_THICK_OR_THIN, _T("Use Thick")));
    
    // Add combo boxes for pen thicknesses
    CMFCRibbonComboBox* pThinComboBox = new CMFCRibbonComboBox(
       ID_PEN_THIN_WIDTH, 0, 20, "Thin Pen :", -1);
    pThinComboBox->AddItem(_T("1"), 1);
    pThinComboBox->AddItem(_T("2"), 2);
    pThinComboBox->AddItem(_T("3"), 3);
    pThinComboBox->AddItem(_T("4"), 4);
    pThinComboBox->AddItem(_T("5"), 5);
    pThinComboBox->AddItem(_T("6"), 6);
    pThinComboBox->AddItem(_T("7"), 7);
    pThinComboBox->AddItem(_T("8"), 8);
    pThinComboBox->AddItem(_T("9"), 9);
    pThinComboBox->SelectItem(1);
    pPanelPen->Add(pThinComboBox);
    CMFCRibbonComboBox* pThickComboBox = new CMFCRibbonComboBox(
       ID_PEN_THICK_WIDTH, 0, 20, "Thick Pen:", -1);
    pThickComboBox->AddItem(_T("5"), 5);
    pThickComboBox->AddItem(_T("6"), 6);
    pThickComboBox->AddItem(_T("7"), 7);
    pThickComboBox->AddItem(_T("8"), 8);
    pThickComboBox->AddItem(_T("9"), 9);
    pThickComboBox->AddItem(_T("10"), 10);
    pThickComboBox->AddItem(_T("11"), 11);
    pThickComboBox->AddItem(_T("12"), 12);
    pThickComboBox->AddItem(_T("13"), 13);
    pThickComboBox->AddItem(_T("14"), 14);
    pThickComboBox->AddItem(_T("15"), 15);
    pThickComboBox->AddItem(_T("16"), 16);
    pThickComboBox->AddItem(_T("17"), 17);
    pThickComboBox->AddItem(_T("18"), 18);
    pThickComboBox->AddItem(_T("19"), 19);
    pThickComboBox->AddItem(_T("20"), 20);
    pThickComboBox->SelectItem(0);
    pPanelPen->Add(pThickComboBox);
    
  2. The new combo boxes do not correspond to any existing menu items. Therefore, we must create menu items for each pen option.

    1. In the Resource View window, open the IDR_SCRIBBTYPE menu resource.

    2. Click Pen to open the Pen menu. Then click Type Here and enter Thi&n Pen.

    3. Right-click the text you just entered to open the Properties dialog box, and then change the ID property to ID_PEN_THIN_WIDTH.

    4. We must also create an event handler for each pen menu item. Right-click the Thi&n Pen menu item that you just created and then click Add Event Handler.... The Event Handler Wizard appears.

    5. From the Wizard's Class list list box, select CScribbleDoc and then click the Add and Edit button. This creates an event handler named CScribbleDoc::OnPenThinWidth.

  3. Add the following code to CScribbleDoc::OnPenThinWidth.

    // Get a pointer to the ribbon bar
    CMFCRibbonBar* pRibbon = ((CMDIFrameWndEx*) AfxGetMainWnd())->GetRibbonBar();
    ASSERT_VALID(pRibbon);
    // Get a pointer to the Thin Width combo box
    CMFCRibbonComboBox* pThinComboBox = DYNAMIC_DOWNCAST(
       CMFCRibbonComboBox, pRibbon->FindByID(ID_PEN_THIN_WIDTH));
    //Get the selected value
    int nCurSel = pThinComboBox->GetCurSel();
    if (nCurSel >= 0)
    {
       m_nThinWidth = (int) pThinComboBox->GetItemData(nCurSel);
    }
    // Create a new pen using the selected width
    ReplacePen();  
    
  4. Next, we create a menu item and event handlers for the thick pen.

    1. In the Resource View window, open the IDR_SCRIBBTYPE menu resource.

    2. Click Pen to open the pen menu. Then click Type Here and enter Thic&k Pen.

    3. Right-click the text that you just entered to display the Properties dialog box. Change the ID property to ID_PEN_THICK_WIDTH.

    4. Right-click the Thick Pen menu item you just created and click Add Event Handler…. The Event Handler Wizard appears.

    5. From the Wizard's Class list list box, select CScribbleDoc and then click the Add and Edit button. This creates an event handler named CScribbleDoc::OnPenThickWidth.

  5. Add the following code to CScribbleDoc::OnPenThickWidth.

    // Get a pointer to the ribbon bar
    CMFCRibbonBar* pRibbon = ((CMDIFrameWndEx *) AfxGetMainWnd())->GetRibbonBar();
    ASSERT_VALID(pRibbon);
    CMFCRibbonComboBox* pThickComboBox = DYNAMIC_DOWNCAST(
       CMFCRibbonComboBox, pRibbon->FindByID(ID_PEN_THICK_WIDTH));
    // Get the selected value
    int nCurSel = pThickComboBox->GetCurSel();
    if (nCurSel >= 0)
    {
       m_nThickWidth = (int) pThickComboBox ->GetItemData(nCurSel);
    }
    // Create a new pen using the selected width
    ReplacePen();
    
  6. Save the changes and then build and run the application. New buttons and combo boxes should appear. Try using different pen widths to scribble.

[go to top]

Adding a Color Button to the Pen Panel

Although black and white is nice, color is livelier. Next, we add a CMFCRibbonColorButton object that enables the user to scribble in color.

To add a color button to the Pen panel

  1. Before we add the color button, we create a menu item for the color button. In the Resource View window, open the IDR_SCRIBBTYPE menu resource. Click the Pen menu item to open the Pen menu. Then click Type Here and enter &Color. Right-click the text that you just entered to display the Properties dialog box. Change the ID to ID_PEN_COLOR.

  2. Add the following code to the CMainFrame::OnCreate method, immediately after the code that creates the thick pen combo box.

    CMFCRibbonColorButton* pColorBtn = new CMFCRibbonColorButton(
       ID_PEN_COLOR, _T("Color"), TRUE, -1, 1);
    pColorBtn->SetAlwaysLargeImage();
    pColorBtn->SetColor(RGB(0,0,0)); // Black is the initial color
    pColorBtn->SetDefaultCommand(FALSE);
    pPanelPen->Add(pColorBtn);
    
  3. Save the changes and then build and run the application. The new color button should appear on the Pen panel. However, it cannot be used because it does not have an event handler. In the next procedure we add an event handler for the color button.

[go to top]

Adding a Color Member to the Document Class

Because Scribble 1.0 did not have color pens, we must write an implementation for them. To store the document's pen color, we add a new member to the document class CscribbleDoc.

To add a color member to the document class

  1. In scribdoc.h, in the CScribbleDoc class, find the // Attributes section. Add the following lines of code after the definition of the m_nThickWidth data member.

    // Current pen color
    COLORREF   m_penColor;
    
  2. Each document contains a list of stokes that the user has already drawn. Each stroke is defined by a CStroke object. The CStroke class does not include information about pen color. Therefore, we must modify the class. In scribdoc.h, in the CStroke class, add the following lines of code after the definition of the m_nPenWidth data member.

    // Pen color for the stroke
    COLORREF   m_penColor;
    
  3. In scribdoc.h, add a new CStroke constructor whose parameters specify a width and color. Add the following line of code after the CStroke(UINT nPenWidth); statement.

    CStroke(UINT nPenWidth, COLORREF penColor);
    
  4. In scribdoc.cpp, add the implementation of the new CStroke constructor. Add the following code after the implementation of the CStroke::CStroke(UINT nPenWidth) constructor.

    // Constructor that uses the document's current width and color
    CStroke::CStroke(UINT nPenWidth, COLORREF penColor)
    {
       m_nPenWidth = nPenWidth;
       m_penColor = penColor;
       m_rectBounding.SetRectEmpty();
    }
    
  5. Change the second line of the CStroke::DrawStroke method as follows.

    if (!penStroke.CreatePen(PS_SOLID, m_nPenWidth, m_penColor))
    
  6. Set the default pen color for the document class. In scribdoc.cpp, add the following lines to CScribbleDoc::InitDocument, after the m_nThickWidth = 5; statement.

    // default pen color is black
    m_penColor = RGB(0,0,0); 
    
  7. In scribdoc.cpp, change the first line of the CScribbleDoc::NewStroke method to the following.

    CStroke* pStrokeItem = new CStroke(m_nPenWidth, m_penColor);
    
  8. Change the last line of the CScribbleDoc::ReplacePen method to the following.

    m_penCur.CreatePen(PS_SOLID, m_nPenWidth, m_penColor);
    
  9. You added the m_penColor member in a previous step. Now, create an event handler for the color button that sets the member.

    1. In the Resource View window, open the IDR_SCRIBBTYPE menu resource.

    2. Right-click the Color menu item and click Add Event Handler…. The Event Handler Wizard appears.

    3. From the Wizard's Class list list box, select CScribbleDoc and then click the Add and Edit button. This creates the CScribbleDoc::OnPenColor event handler stub.

  10. Replace the stub for the CScribbleDoc::OnPenColor event handler with the following code.

    void CScribbleDoc::OnPenColor()
    {
    // Change pen color to reflect color button's current selection
    CMFCRibbonBar* pRibbon = ((CMDIFrameWndEx*) AfxGetMainWnd())->GetRibbonBar();
    ASSERT_VALID(pRibbon);
    CMFCRibbonColorButton* pColorBtn = DYNAMIC_DOWNCAST(
       CMFCRibbonColorButton, pRibbon->FindByID(ID_PEN_COLOR));
    m_penColor = pColorBtn->GetColor();
    // Create new pen using the selected color
    ReplacePen();
    }
    
  11. Save the changes and then build and run the application. You should be able to press the color button and change the pen's color.

[go to top]

Initializing Pens and Saving Preferences

Next, initialize the color and width of the pens. Finally, save and load a color drawing from a file.

To initialize controls on the ribbon bar

  1. Initialize the pens on the ribbon bar.

    Add the following code to scribdoc.cpp, in the CScribbleDoc::InitDocument method, after the m_sizeDoc = CSize(200,200) statement.

    // Reset the ribbon UI to its initial values
    CMFCRibbonBar* pRibbon = 
       ((CMDIFrameWndEx*) AfxGetMainWnd())->GetRibbonBar();
    ASSERT_VALID(pRibbon);
    CMFCRibbonColorButton* pColorBtn = DYNAMIC_DOWNCAST(
       CMFCRibbonColorButton, 
       pRibbon->FindByID(ID_PEN_COLOR));
    // Set ColorButton to black
    pColorBtn->SetColor(RGB(0,0,0));  
    CMFCRibbonComboBox* pThinComboBox = DYNAMIC_DOWNCAST(
       CMFCRibbonComboBox, 
       pRibbon->FindByID(ID_PEN_THIN_WIDTH));
    // Set Thin pen combobox to 2
    pThinComboBox->SelectItem(1); 
    CMFCRibbonComboBox* pThickComboBox = DYNAMIC_DOWNCAST(
       CMFCRibbonComboBox, 
       pRibbon->FindByID(ID_PEN_THICK_WIDTH));
    // Set Thick pen combobox to 5
    pThickComboBox->SelectItem(0);
    
  2. Save a color drawing to a file. Add the following statement to scribdoc.cpp, in the CStroke::Serialize method, after the ar << (WORD)m_nPenWidth; statement.

    ar << (COLORREF)m_penColor;
    
  3. Finally, load a color drawing from a file. Add the following line of code, in the CStroke::Serialize method, after the m_nPenWidth = w; statement.

    ar >> m_penColor;
    
  4. Now scribble in color and save your drawing to a file.

[go to top]

Success!

You have successfully updated the MFC Scribble application. Use this walkthrough as a guide when you modify your existing applications.

See Also

Tasks

Walkthrough: Updating the MFC Scribble Application (Part 1)

Other Resources

Walkthroughs (MFC Feature Pack)