Home > OS >  Dynamically Change Ribbon Image
Dynamically Change Ribbon Image

Time:09-04

I'm trying to dynamically change a button image on a custom ribbon in Access 365.

I so far have this ribbon xml:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onl oad="OnRibbonLoad" loadImage="LoadImages">
    <ribbon startFromScratch="false">
        <tabs>
            <tab id="elcdb" label="EDB">
                <group id="ElecDBMaint" label="Maintenance">
                    <splitButton id="MySplitButton2" size="large"> 
                        <button id="Button50" label="Large Button with Menu"/> 
                        <menu id="Menu20" itemSize="normal"> 
                            <button id="Button60" label="First"/> 
                            <button id="Button70" label="Second"/> 
                            <button id="Button80" label="Third"/> 
                        </menu> 
                    </splitButton> 
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

Which gives an ribbon which looks like this:

enter image description here

The idea is that after a button is clicked, the image will change to show the last clicked button so that when the button is clicked again, it executes the previous action rather than the user drilling down each and every time through the menus to find the previous button...

I guess there has to be a GetImage call back in there to set the image but I cannot find where to put it. I also need to know how the callback sets the image - I'm looking for the inbuilt function images not external ones (FileSave, FileSendAsAttachment, FileQuickPrint for example).

I'm also guessing the OnAction button somehow needs to keep track of the last function unless there is another callback which can determine the state of the button???

I have managed to find a basis which looks like this: enter image description here

You can hover over the image and click on the image. You can also click on the text to reveal the menu and associated buttons...

and the ribbon xml is

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onl oad="OnRibbonLoad" loadImage="LoadImages">
    <ribbon startFromScratch="false">
        <tabs>
            <tab id="elcdb" label="EDB">
                <group id="elcdb" label="EDB">
                    <splitButton id="MySplitButton2" size="large"> 
                        <button id="Button50" label="Large Button with Menu" imageMso="LeaveReader"/> 
                        <menu id="Menu20" itemSize="normal"> 
                            <button id="Button60" label="First"/> 
                            <button id="Button70" label="Second"/> 
                            <button id="Button80" label="Third"/> 
                        </menu> 
                    </splitButton> 
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

CodePudding user response:

enter image description here

You could do this with the getLabel and getImage properties. You just need to invalidate the ribbon (or just the control) once the new values have been set.

The sample ribbon xml would be this:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onl oad="CustomRibbon_onLoad">
    <ribbon>
        <tabs>
            <tab id="myTab" label="Test" insertAfterMso="TabHome">
                <group id="myGroup" label="Try This">
                    <splitButton id="mySplitButton" size="large" >
                        <button id="mainButton"
                        getLabel="SplitButton_getLabel"
                        getImage="SplitButton_getImage"
                        onAction="SplitButton_onAction" /> 
                        <menu id="buttonMenu" itemSize="normal"> 
                            <button id="subButton1" label="First" imageMso="Club" onAction="SubButton1_onAction"/> 
                            <button id="subButton2" label="Second" imageMso="Diamond" onAction="SubButton2_onAction"/> 
                            <button id="subButton3" label="Third" imageMso="Heart" onAction="SubButton3_onAction"/> 
                            <button id="subButton4" label="Fourth" imageMso="Spade" onAction="SubButton4_onAction"/> 
                        </menu> 
                    </splitButton> 
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

And in a module the code would be:

Option Explicit
    
#If VBA7 Then
Public Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    destination As Any, _
    source As Any, _
    ByVal length As Long)
#Else
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    destination As Any, _
    source As Any, _
    ByVal length As Long)
#End If

Private mRibbonUI As IRibbonUI
Private mButtonIndex As Long
Private mButtonLabels(4) As String
Private mButtonImages(4) As String


Public Sub CustomRibbon_onLoad(ribbonUI As IRibbonUI)
    
    Set mRibbonUI = ribbonUI
    wsSettings.Range("A1").value = ObjPtr(mRibbonUI)
    mButtonIndex = 0
    mButtonLabels(0) = "Select"
    mButtonLabels(1) = "First"
    mButtonLabels(2) = "Second"
    mButtonLabels(3) = "Third"
    mButtonLabels(4) = "Fourth"
    mButtonImages(0) = "HappyFace"
    mButtonImages(1) = "Club"
    mButtonImages(2) = "Diamond"
    mButtonImages(3) = "Heart"
    mButtonImages(4) = "Spade"
End Sub

Public Sub SplitButton_getLabel(ctrl As IRibbonControl, ByRef value)
    value = mButtonLabels(mButtonIndex)
End Sub
Public Sub SplitButton_getImage(ctrl As IRibbonControl, ByRef value)
    value = mButtonImages(mButtonIndex)
End Sub

Public Sub SplitButton_onAction(ctrl As IRibbonControl)
    ExecuteAction
End Sub

Public Sub SubButton1_onAction(ctrl As IRibbonControl)
    mButtonIndex = 1
    CustomRibbon.Invalidate
    ExecuteAction
End Sub

Public Sub SubButton2_onAction(ctrl As IRibbonControl)
    mButtonIndex = 2
    CustomRibbon.Invalidate
    ExecuteAction
End Sub

Public Sub SubButton3_onAction(ctrl As IRibbonControl)
    mButtonIndex = 3
    CustomRibbon.Invalidate
    ExecuteAction
End Sub

Public Sub SubButton4_onAction(ctrl As IRibbonControl)
    mButtonIndex = 4
    CustomRibbon.Invalidate
    ExecuteAction
End Sub

Private Sub ExecuteAction()
    If mButtonIndex = 0 Then
        MsgBox "You must select an item first."
    Else
        Debug.Print "Action index is: " & mButtonIndex
    End If
End Sub

Private Property Get CustomRibbon() As IRibbonUI
#If VBA7 Then
    Dim aPtr As LongPtr
#Else
    Dim aPtr As Long
#End If
    Dim ribUI As Object

    On Error GoTo EH
    
    If Not mRibbonUI Is Nothing Then
        Set CustomRibbon = mRibbonUI
        Exit Function
    End If
    
    aPtr = wsSettings.Range("A1").Value2
    CopyMemory ribUI, aPtr, LenB(aPtr)
    Set mRibbonUI = ribUI
    Set ribUI = Nothing
    
    Set CustomRibbon = mRibbonUI
    Exit Function
EH:
End Property

It's easy to lose reference to the IRibbonUI object (once the VBA is stopped, for example, the reference is lost), so a common way of dealing with that is to store the pointer somewhere and CopyMemory the pointer to the object if reference is lost.

  • Related