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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
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