Modifying the Ribbon – Part 10

Posted on December 10th, 2006 in Excel,Office 2007,The Ribbon by Ken Puls

The history of posts on the Ribbon can be found at the Ribbon Example Table of Contents.

The purpose of this post is to demonstrate how to use the Ribbon to interact with our application. Specifically, this example has an edit box which will update with the worksheet name every time you change worksheets. In addition, if you change the name in the edit button, then press the "commit" button, it will change the name of the worksheet to your new selection. (Providing the new name is allowed, of course.)

XML Markup Required

Our XML for this example uses the onLoad assignment to capture our ribbonUI object, allowing us to force a rebuild of our ribbon items when needed, as well as the onAction, onChange and getText callbacks.

XML:
  1. <customUI onLoad="OnLoad" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
  2. <ribbon startFromScratch="false">
  3. <tabs>
  4. <tab id = "xlgTab" label="XLG" insertAfterMso="TabView">
  5. <group id="TestTab" label="My Testing Tab">
  6. <editBox id="editBox1" label="New Sheet Name:" onChange="rbnEditBox1_Change" getText="rbnGetText" />
  7. <button id="button1" label="Commit Name" onAction="rbnButton_Click" imageMso="HappyFace" />
  8. </group>
  9. </tab>
  10. </tabs>
  11. </ribbon>
  12. </customUI>

VBA Code Required - ThisWorkbook Module

Again, we have the need to create workbook properties to set and retrieve the values of our ribbon controls. This time, we need to store the name in the editBox, which can be applied as a worksheet name, as well as the RibbonUI object. The editBox property is first used immediately upon opening the workbook, when we assign the active worksheet's name to it. It is then subsequently updated every time a new sheet is activated in the workbook. The code required in the ThisWorkbook module to accomplish this is shown below:

Visual Basic:
  1. Option Explicit
  2.  
  3. 'Private variables to hold state of Ribbon and Ribbon controls
  4. Private pRibbonUI As IRibbonUI
  5. Private sEditBox1Text As String
  6.  
  7. Public Property Let EditBox1Text(s As String)
  8. 'Store the button name
  9. sEditBox1Text = s
  10. End Property
  11.  
  12. Public Property Get EditBox1Text() As String
  13. 'Retrieve the button name
  14. EditBox1Text = sEditBox1Text
  15. End Property
  16.  
  17. Public Property Let ribbonUI(iRib As IRibbonUI)
  18. 'Set RibbonUI to property for later use
  19. Set pRibbonUI = iRib
  20. End Property
  21.  
  22. Public Property Get ribbonUI() As IRibbonUI
  23. 'Retrieve RibbonUI from property for use
  24. Set ribbonUI = pRibbonUI
  25. End Property
  26.  
  27. Private Sub Workbook_Open()
  28. 'Store the name of the active worksheet
  29. ThisWorkbook.EditBox1Text = ActiveSheet.Name
  30. End Sub
  31.  
  32. Private Sub Workbook_SheetActivate(ByVal Sh As Object)
  33. 'Set the name of the worksheet to the text property
  34. With ThisWorkbook
  35. .EditBox1Text = ActiveSheet.Name
  36. .ribbonUI.InvalidateControl editBox1Name
  37. End With
  38. End Sub

VBA Code Required - Standard Module

The following code contains all the callbacks necessary to:

  • Store the ribbonUI object to the Workbook property (via the onLoad routine)
  • Return the text for the editBox control when the RibbonX code requires it (rbnGetText routine)
  • React to manual changes of the text values in the EditBox control (via the rbnEditBox1_Change routine)
  • Respond to the button click requesting a worksheet name change (via the rbnButton_Click routine)
Visual Basic:
  1. Option Explicit
  2.  
  3. Const Btn1Name = "button1"
  4. Public Const editBox1Name = "editBox1"
  5.  
  6. Private Sub OnLoad(ribbon As IRibbonUI)
  7. 'Set the RibbonUI to a workbook property for later use
  8. ThisWorkbook.ribbonUI = ribbon
  9. End Sub
  10.  
  11. Sub rbnGetText(control As IRibbonControl, ByRef returnedVal)
  12. 'Get the text value for the editBox
  13. If control.ID = editBox1Name Then returnedVal = ThisWorkbook.EditBox1Text
  14. End Sub
  15.  
  16. Private Sub rbnEditBox1_Change(control As IRibbonControl, text As String)
  17. 'Store the text value of the editBox for later use.
  18. If control.ID = editBox1Name Then
  19. ThisWorkbook.EditBox1Text = text
  20. End If
  21. End Sub
  22.  
  23. Private Sub rbnButton_Click(control As IRibbonControl)
  24. 'Rename the worksheet
  25. Dim sNewSheetName As String
  26. Dim ws As Worksheet
  27.  
  28. If control.ID = Btn1Name Then
  29. 'Retrieve intended sheet name
  30. sNewSheetName = ThisWorkbook.EditBox1Text
  31.  
  32. 'Check if name is nothing
  33. If Len(sNewSheetName) = 0 Then
  34. MsgBox "I need a name, please.", _
  35. vbOKOnly + vbCritical, "No name entered"
  36. Exit Sub
  37. End If
  38.  
  39. 'Check for sheet name in use
  40. For Each ws In ThisWorkbook.Worksheets
  41. If ws.Name = sNewSheetName Then
  42. MsgBox "Sheet name already used." & vbNewLine & _
  43. "Please pick another", vbOKOnly + vbCritical, _
  44. "Name in use!"
  45. Exit Sub
  46. End If
  47. Next ws
  48.  
  49. 'Would not be here if name not okay so set it
  50. ActiveSheet.Name = sNewSheetName
  51. End If
  52. End Sub

End Result

Once you've saved all the code, close and re-open the workbook. You'll have a custom XLG tab (that you've become used to if you're following the series.) On this tab you'll find a group that looks like this:

The code fires in this order when the workbook is opened up (assuming Macros are enabled):

  • The RibbonX code is loaded, and the XLG tab is added
  • The Workbook_Open event is fired, setting the EditBox1Text property to the name of the active sheet in the workbook
  • The OnLoad procedure runs, capturing the RibbonUI object to a property for later use in triggering callbacks

At this point, you have the XLG tab showing on the Ribbon. When you click that tab, the "GetText" callback for the editBox is executed. This queries the property we just set, and adjusts the text in the editBox to the name of the active worksheet (which we just stored in the EditBox1Text property, as explained above. Because the button's properties are set in the XML, no additional callbacks are required to build the button.
Our Ribbon is now fully loaded, the editbox has a name in it, and the button is ready to be clicked. First though, try navigating to other sheets in the workbook. Every time you activate another worksheet in the workbook, you will trigger the following chain of events:

  • The Workbook_SheetActivate routine is fired as the new worksheet is selected
  • The name of the new sheet is sent to the EditBox1Text property and stored for later use (in the "sEditBox1Text" private variable)
  • The editBox is invalidated, forcing the RibbonX code to be rebuilt
  • During the rebuilding, the rbnGetText routine is called, which subsequently retrieves the worksheet name from the EditBox1Text property and builds it into the refreshed ribbon control

The only thing that looks any different now is that the sheet name will have changed in the edit box. You can click back and forth between sheets to watch it change, although that will probably get stale rather quickly. ;)
So now, try typing something in the editbox and clicking the "Commit Name" button. If you check the active worksheet's tab, you'll see that the name has been updated. This was accomplished by the following actions, triggered when you clicked the button:

  • As control passes from the editBox field to the button, the rbnEditBox1_Change routine is fired, which sends the value of the editBox to the EditBox1Text property for later use
  • Once the above routine is complete, the rbnButton_Click routine is fired
  • Control id is checked to make sure that we are reacting to the correct button. (Not really needed here, but would be if we added another button which used the same onAction routine.)
  • The editBox's value is assigned to a string for checking
  • The string is evaluated to make sure it is not blank. If it is, we tell the user and exit the routine without changing the name
  • The string is checked to make sure that it doesn't conflict with an existing sheet name. If it is, the user is informed and we exit the routine without making changes
  • If the string passed the above tests, we change the worksheet name.

While I can't really think of a good reason that you would want to add this functionality to the ribbon, I hope that it does a decent job of explaining the "how" of ribbon control and application interaction. :)

One Response to 'Modifying the Ribbon – Part 10'

Subscribe to comments with RSS or TrackBack to 'Modifying the Ribbon – Part 10'.

  1. benzadeus said,

    on October 28th, 2011 at 8:36 am

    Thank you for this great example.

Post a comment