Finding Ribbon Images

Now that Excel 2003 is almost completely out of my life, it’s time to get my many add-ins ribbonized. Here’s what my UIHelpers ribbon looks like.

I used the Custom UI Editor and it was horrible. Did they put the VBE team on that project? I think I’ll find an alternative for the next add-in I convert. I don’t mind XML so much. The absolute worst part of creating a ribbon is finding a suitable button image. I downloaded Jim Rech’s add-in from Ron’s site. I scrolled through some button pages, but with 3,500 images, that wasn’t going to work.

Eventually, I changed the IsAddin property so I could see the list of image names. Then I filtered the names based on some keywords. Once I had a good candidate, I’d go back up to the ribbon, find that button, and look at it. This was much better than browsing through all of the pages hoping I’d find something suitable.

As you can imagine, I couldn’t leave well enough alone. I modified Jim’s code so I could filter the images based on their names directly on the ribbon. Jim had a nice system for what he wanted to do and I spent far too much time trying to shoehorn this new feature into that system. After a while, I started, more or less, from scratch. I should have done that from the start.

I started by adding a textbox to the ribbon where the filter term will go. It looks like this:

I don’t know what all that means, I just copied Jim’s and changed a few things. For the control handling part, I created two variables: mcolFiltered and mcolShown. mcolFiltered is a collection that holds all of the controls that match the filter. If there’s no filter, it simply holds all of the controls. When the ribbon loads, it sets up some module-level variables.

Private Sub FilterImagesRibbonLoaded(ribbon As IRibbonUI)

Set mRib = ribbon
mlStart = 1
mlSize = eButtonSize.Normal
ResetListToUse
msWhat = vbNullString
SetButtons

End Sub

mlStart determines which member of the collection to show first. ResetListToUse gets the button names from a spreadsheet. msWhat is the filter term – set to nothing to start.

Private Sub SetButtons()

Dim i As Long

Set mcolShown = New Collection
Set mcolFiltered = New Collection

For i = LBound(mvaButtons, 1) To UBound(mvaButtons, 1)
If InStr(1, mvaButtons(i, 1), msWhat, vbTextCompare) Then
mcolFiltered.Add mvaButtons(i, 1), mvaButtons(i, 1)
End If
Next i

If mlStart + ButtonsShown > mcolFiltered.Count Then
mlStart = mcolFiltered.Count - ButtonsShown + 1
End If

If mlStart < 1 Then mlStart = 1 End If For i = mlStart To mcolFiltered.Count mcolShown.Add mcolFiltered(i), mcolFiltered(i) If mcolShown.Count >= ButtonsShown Then Exit For
Next i

End Sub

SetButtons handles what’s shown. First mcolFiltered is populated with all the control names that match the filter. Then mlStart is validated to make sure it’s within the range. Lastly, mcolShown is populated with which portion of mcolFiltered is on display. Most of the rest of the code just sets one or more module-level variable and calls SetButtons. Here’s some more code, just for fun.

Private Function ButtonsShown() As Long

If mlSize = eButtonSize.Normal Then
ButtonsShown = eButtonShow.Normal
Else
ButtonsShown = eButtonShow.Large
End If

End Function

Private Sub EditboxEntry(control As IRibbonControl, text As String)

Dim lNum As Long

lNum = CLng(Val(text))

If lNum <= 0 Then mlStart = 1 ElseIf lNum >= mcolFiltered.Count - ButtonsShown + 1 Then
mlStart = mcolFiltered.Count - ButtonsShown + 1
Else
mlStart = lNum
End If

SetButtons
mRib.Invalidate

End Sub

Private Sub SizeCBHandler(control As IRibbonControl, ByRef returnedVal)

If returnedVal Then 'Large checkbox checked
mlSize = eButtonSize.Large
Else
mlSize = eButtonSize.Normal
End If
SetButtons
mRib.Invalidate

End Sub

Private Sub GetNextGroup(control As IRibbonControl)

If ShiftDown Then
mlStart = mcolFiltered.Count - ButtonsShown
Else
mlStart = mlStart + ButtonsShown
End If
SetButtons
mRib.Invalidate

End Sub

Here’s the ribbon showing all of the controls with “filter” in their name.

As verbose as the image names are, they don’t contain enough information to do a proper search. Searching for “filter” works well enough, but if you want something related to money, you won’t find one search term that gets the job done. We need some meta data around each of the images. The first image is of a zero and is named “_0”. That image needs to turn up for searches such as zero, nil, number, digit, telephone, and probably some others. With 3,500 images, I’m not too interested in filling out all of that meta data. We need to crowd source it. Or hire some poor people.

Come to think of it, all those captchas that you have to type to prove you’re human are a lot of wasted effort. I should make a captcha system that shows a picture and asks the user to type two words that come to mind. I won’t actually check the words against anything, but I’ll use them to build my meta database for these images. Sure the captcha won’t work, but by the time people figure that out, I’ll already have my data. Brilliant.

You can download RibbonButtons.zip