问题
I've started using the Access Ribbon for menus in my database, but now I'm afraid I've come to an impasse.
I'd like to use my own images for the icons in the ribbon, but am having loads of difficulty accomplishing this task.
The code is just below, but the error message I keep getting is that Access cannot run the macro or callback function 'getImages'.
Ribbon xml Code:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<ribbon startFromScratch="true">
<tabs>
<tab id="tMainMenu" label="Main Menu">
<group id="Developer">
<button id="DevTools1"/>
</group>
<group id="MainMenuSpacer1">
</group>
<group id="gSupport">
<button id="Support1" label="Custom Image" getImage="getImages"/>
</group>
<group id="MainMenuSpacer2">
</group>
<group id="gShutdown">
<button id="Shutdown"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
VBA Procedure Code:
Public Sub getImages(control As IRibbonControl, ByRef image)
If irc.ID = "Support1" Then
MyPath = "J:\Images\OperatorAssistantButton1.png"
Set image = LoadPicture(MyPath)
End If
End Sub
My company does not have the 12.0 Reference. We are using 15.0
回答1:
Keep in mind that there are TWO types of image loads.
1 One time image load.
A one-time image load is used for “most” image loads. This is used when you want a custom icon, but are NOT going to change the image once loaded. This approach is thus used for “most” custom image loads for the ribbon.
2 Runtime ability to change image.
This is used when you want the image to be able to not only be loaded, but ALSO want to have the image change - say an image that shows the weather as sunny, and then you change it to a cloud for cloudy.
So VERY important to distinguish between your goal, and the type of image load you need and want.
One time image load example
For “general” image load and setting in the ribbon, you thus ONLY ONE TIME specify the routine you will use (at the start of the ribbon xml). This routine is then used for ALL of your image settings and you do NOT specify the call back routine for each control.
You thus use the “image” attribute setting for each control, but ONLY specify the call back routine one time.
The ribbon code will thus look like this:
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"
loadImage="CallBackLoadImage"
onLoad="MyRibbonLoadA">
<group id="group1" label="Basic Button Attributes Examples">
<button id="button1" label="Button1"
size="large"
getEnabled="MyEnable"
getVisible="MyVisible"
image="CokeClassic.png"
onAction="=Bt1()"
supertip= "example load a image without ability to change"
/>
<button id="button2" label="button2"
size="large"
getEnabled="MyEnable"
image="CokeZero.png"
onAction="=Bt2()"
/>
Note in above HOW we set the image for the first button.
image="CokeClassic.png"
and for second button we ue:
image="CokeZero.png"
So in effect, we hard code and specify the image in the XML of the ribbon. And in above at the start we set the GLOBAL image load routine that is to be use for ALL images we specify in the ribbon.
The routine we will use/call for all these images is thus specified at the start:
loadImage="CallBackLoadImage"
Note how this is ONLY done ONE TIME and at the start of the ribbon XML – you do NOT specify this call back for each button.
The VBA routine (CallBAckLoadImage in our example) has to be placed in a standard VBA code module (not a class, and not in a forms code module). The ribbon load code we have is thus this:
Sub CallbackLoadImage(strImage As String, _
ByRef image)
Dim strImagePath As String
' Callback loadImage
strImagePath = CurrentProject.Path & "\ribbon\" & strImage
Set image = LoadPicture(strImagePath)
End Sub
In above, note how our code “assumes” that a folder called ribbon will be placed in the SAME folder as where the front end (accDB/accDE) is running. Thus we don’t hard code any path names, and assume that a ribbon “icon” folder will always exist in the same folder as where we run the application from. So we can copy, rename the folder, or move it anywhere, and our image load code will still run.
So just keep in mind that you do NOT specify the call back for EACH button – only one time. And NOTE HOW the image name is automatic passed to the routine we call. So the “image = some image” is rather nice, since we don’t require SPECIAL code to pluck out or figure out what image we want.
Case 2 - runtime change of image.
We want to CHANGE the icons at runtime. As noted, for most images, we use approach #1, but in some cases we need and want a dynamic routine. However, on ribbon startup, this means the code will have to supply some default type of image, and thus for this example, I used the “tag” setting to set a default ribbon.
So our button code now looks like:
<button id="Weather" label = "The Weather button"
size="large"
getImage="MyImage" tag="sunny.png"
onAction= "=BtWeather()"
/>
So in above WE DO set the call back for EACH button etc.
The call back code looks like:
Public Sub MyImage(control As IRibbonControl, ByRef image)
Dim strImagePath As String
Dim strImage As String
' for the 1st call when ribbon loads there no images set. So we
' use the tag as kludge workaround to set the starting image
If strGlobalImage = "" then
strImage = control.Tag
End If
If strImage <> "" Then
If Left(strImage, 4) = "mso." Then
image = Mid(strImage, 5)
Else
strImagePath = CurrentProject.Path & "\ribbon\" & strImage
Set image = LoadPicture(strImagePath)
End If
End If
End Sub
Note in above, I also have provisions for using built-in images – because there are so many useful ones, then I adopted the standard that I can place the text “iso.ImageName” for built-in icons. So if you use "iso.BuiltInImageName", then above will work.
I also do this for process #1 above, and thus I have:
Sub CallbackLoadImage(strImage As String, _
ByRef image)
Dim strImagePath As String
' Callback loadImage
If Left(strImage, 4) = "mso." Then
strImage = Mid(strImage, 5)
image = strImage
Else
strImagePath = CurrentProject.Path & "\ribbon\" & strImage
Set image = LoadPicture(strImagePath)
End If
End Sub
So above allows me to use any of the “many” icons built into office – there are lot of useful ones.
So keep a “STRONG” distinction between the two kinds of image loads:
1) you want a image for a button etc.
2) you want to CHANGE the image after loaded to other kinds of images for status etc.
Last but not least: For any button, it is REALLY a pain to have to declare a set of variables that hold the state of a SINGLE button. You have: Visible, Enabled, Label text Image
So for each button, you in general have to declare a variable to hold all the states. For just 2-3 buttons, you need like 12 global variables to hold these states of the button. So I build a class that automatic creates and does all the dirty work for you.
You can find the above same code, and more in this sample working of mine here:
http://www.kallal.ca/Ribbon/ribbon.htm
The main advantage of above is you don’t have to declare new variables for each new button etc. that you want dynamic change of the image or label text.
来源:https://stackoverflow.com/questions/52915787/access-2013-custom-images-for-the-ribbon