So we've explored the file formats, created the shell for a dictator application, made some basic ribbon, tab, group and control changes and customised the Office menu. We've re-purposed some Microsoft controls to our own use and now we will be running at pace through some of the other controls available to you. I doubt we will cover all of them, but you can download a bunch of my files here, which demonstrate more of what you are learning here and also contain a 'popular' control and attribute listing. So...let's get started.
The Core Of Our Model
As usual we will start with our basic building blocks of declaring a customUI and the ribbon itself, it's startFromScratch attribute and a custom tab, which we will place after the built-in add-ins tab, like so:
<customUI onLoad="loadRibbon" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon startFromScratch="false">
<tabs>
<tab id="myTab1" label="Nick's Tab" insertAfterMso="TabAddIns" visible="true" keytip="Z">
</tabs>
</ribbon>
</customUI>
Notice that for the first time we have used the onLoad attribute of the customUI which will fire the callback VBA called loadRibbon. This will enable us to capture the ribbon object and change stuff later 'on the fly' by invalidating it.
Hopefully by now you are able to read and understand this basic format that makes the core of any customisation, remember, you must have an id for every control, within a collection, (remember the ribbon can only be singular, so doesn't need one), and this must be unique in your project and either is a custom (created by you) id, or a built-in (created by Microsoft) idMso. You will find this rule throughout your customisations, for example, above we use insertAfterMso meaning insert this tab after the built-in 'add-ins' one.
Adding A Group and Button
To the same code above, we can add our first custom group with a custom button. This button has it's own onAction callback to VBA to handle the code when the button is pressed. The code at this stage is as below:
<customUI onLoad="loadRibbon" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon startFromScratch="false">
<tabs>
<tab id="myTab1" label="Nick's Tab" insertAfterMso="TabAddIns" visible="true" keytip="Z">
<group id="Group1" label="Button" visible="true">
<button id="Button1" imageMso="FileOpen" keytip="A" label="Button 1"
onAction="OpenFileButton" screentip="This is the screentip of button1"
size="large" supertip="This is the supertip of button1"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
visible="true">
<button id="Button1" imageMso="FileOpen" keytip="A" label="Button 1"
onAction="OpenFileButton" screentip="This is the screentip of button1"
size="large" supertip="This is the supertip of button1"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
The group has an id, is visible and has a label, which is the description that sits at the bottom on the group, as the below image of our 'growing tab shows. Hopefully you can also pick the other 'bits' from the code that created it, e.g. The tab label, where it's positioned, the size of the button, (large), that we have 'nicked' the imageMso for file>open and what a screentip and supertip look like.
Having a 'large' button exposes another feature of the ribbon and that is re-sizing. It will endeavour, as above to show it using it's full size, but if the overall size of the application window does not allow, it will first drop it's label and then shrink it's size down to small.
At this stage of course, loading the file will fire the onLoad callback and as there is no code it will return an error that the relevant code is not available. We'll take a look at the callback code once we have built our tab.
Buttons, Boxes and Separators.
One button in a group, as in the previous section is fine, but as soon as you add more buttons in a group, coupled with the 're-size' effect and we must use some 'hidden' controls, to stop the controls from flowing in undesirable directions. We use Boxes to achieve that, together with separators. Below is the code to add a new group ("Group2") and two 'sets' of three buttons, in vertical boxes with a separator dividing the two 'sets' of three. Whilst you cannot see the boxes, I have drawn them in the resulting tab image below the code, so you can visualise it in your own mind. You can of course see the 'vertical' separator. (It is only a vertical separator as it sits between two vertically aligned boxes, even in the code as you can see!).
<customUI onLoad="loadRibbon" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon startFromScratch="false">
<tabs>
<tab id="myTab1" label="Nick's Tab" insertAfterMso="TabAddIns" visible="true" keytip="Z">
<group id="Group1" label="Button" visible="true">
<button id="Button1" imageMso="FileOpen" keytip="A" label="Button 1"
onAction="OpenFileButton"
screentip="This is the screentip of button1"
size="large" supertip="This is the supertip of button1"/>
</group>
<group id="Group2" label="Boxes and Buttons">
<box id="box1" boxStyle="vertical">
<button id="button1B" label="Button 1" onAction="ButtonPressedMsgBox"/>
<button id="button2B" label="Button 2" onAction="ButtonPressedMsgBox"/>
<button id="button3B" label="Button 3" onAction="ButtonPressedMsgBox"/>
</box>
<separator id="separator1"/>
<box id="box2" boxStyle="vertical">
<button id="buttonA" label="Button A" onAction="ButtonPressedMsgBox"/>
<button id="buttonB" label="Button B" onAction="ButtonPressedMsgBox"/>
<button id="buttonC" label="Button C" onAction="ButtonPressedMsgBox"/>
</box>
</group>
</tab>
</tabs>
</ribbon>
</customUI>

If we now do the same with two sets of buttons in horizontal boxes, you will hopefully see the difference, both in the code and the ribbon image. Remember, horizontal buttons do not have a corresponding horizontal separator, separators do not have a style attribute...maybe v.Next!
<customUI onLoad="loadRibbon" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon startFromScratch="false">
<tabs>
<tab id="myTab1" label="Nick's Tab" insertAfterMso="TabAddIns" visible="true" keytip="Z">
<group id="Group1" label="Button" visible="true">
<button id="Button1" imageMso="FileOpen" keytip="A" label="Button 1"
onAction="OpenFileButton"
screentip="This is the screentip of button1"
size="large" supertip="This is the supertip of button1"/>
</group>
<group id="Group2" label="VBoxes and Buttons">
<box id="box1" boxStyle="vertical">
<button id="button1B" label="Button 1" onAction="ButtonPressedMsgBox"/>
<button id="button2B" label="Button 2" onAction="ButtonPressedMsgBox"/>
<button id="button3B" label="Button 3" onAction="ButtonPressedMsgBox"/>
</box>
<separator id="separator1"/>
<box id="box2" boxStyle="vertical">
<button id="buttonA" label="Button A" onAction="ButtonPressedMsgBox"/>
<button id="buttonB" label="Button B" onAction="ButtonPressedMsgBox"/>
<button id="buttonC" label="Button C" onAction="ButtonPressedMsgBox"/>
</box>
</group>
<group id="Group3" label="HBoxes and Buttons">
<box id="box3" boxStyle="horizontal">
<button id="button1C" label="Button H1" imageMso="FileOpen" onAction="ButtonPressedMsgBox"/>
<button id="button2C" label="Button H2" imageMso="FileOpen" onAction="ButtonPressedMsgBox"/>
</box>
<box id="box4" boxStyle="horizontal">
<button id="buttonHA" label="Button HA" onAction="ButtonPressedMsgBox"/>
<button id="buttonHB" label="Button HB" onAction="ButtonPressedMsgBox"/>
</box>
<box id="box5" boxStyle="horizontal">
<button id="buttonHZ" label="Button HZ" onAction="ButtonPressedMsgBox"/>
<button id="buttonHX" label="Button HX" onAction="ButtonPressedMsgBox"/>
</box>
</group>
</tab>
</tabs>
</ribbon>
</customUI>

You may notice in the above code snippets that we are using the same callback on the button onAction attribute. This allows us to make a decision based on the button pressed, using the passed 'parent buttons' id, like so. For a button callback there are three captured properties, id, context and tag. Any or all of these can be used, stored in variables, on worksheets, in range names, etc.
Sub OpenFileButton(control As IRibbonControl)
If control.ID = "button1" Then
'do this
Else
'do this
End If
End Sub
The Gallery and dialogLauncher Controls.
Lastly for this part, we will look at two new controls in this first iteration of the ribbon. The gallery, (this is like the styles dropdown image store) and the dialogLauncher, which is a container control, carrying a button, that looks like a little diagonal arrow in the bottom right hand corner of a group, allowing you to fire a dialog (built-in or custom) on it being pressed.
The Gallery
Currently you cannot customise built-in galleries, but you can build your own and load your image collateral through the Custom UI Editor. This part is simple, just open the editor, click on the image toolbar button, navigate to your image files and select OK. This will load them in the side of the UI editor so they an be selected and loaded into the file. A gallery is once again a container control, with 'items' below it that actually hold the images and fire callbacks, etc. It can also contain buttons, but these must appear below any items and they are the menu options that sit below the gallery items, like 'New Cell Style,,,' on the cell style gallery on the home tab.
The added code is below, with the image of the resulting controls below that:
<customUI onLoad="loadRibbon" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<ribbon startFromScratch="false">
<tabs>
<tab id="myTab1" label="Nick's Tab" insertAfterMso="TabAddIns" visible="true" keytip="Z">
<group id="Group1" label="Button" visible="true">
<button id="Button1" imageMso="FileOpen" keytip="A" label="Button 1"
onAction="OpenFileButton"
screentip="This is the screentip of button1"
size="large" supertip="This is the supertip of button1"/>
</group>
<group id="Group2" label="VBoxes and Buttons">
<box id="box1" boxStyle="vertical">
<button id="button1B" label="Button 1" onAction="ButtonPressedMsgBox"/>
<button id="button2B" label="Button 2" onAction="ButtonPressedMsgBox"/>
<button id="button3B" label="Button 3" onAction="ButtonPressedMsgBox"/>
</box>
<separator id="separator1"/>
<box id="box2" boxStyle="vertical">
<button id="buttonA" label="Button A" onAction="ButtonPressedMsgBox"/>
<button id="buttonB" label="Button B" onAction="ButtonPressedMsgBox"/>
<button id="buttonC" label="Button C" onAction="ButtonPressedMsgBox"/>
</box>
</group>
<group id="Group3" label="HBoxes and Buttons">
<box id="box3" boxStyle="horizontal">
<button id="button1C" label="Button H1" imageMso="FileOpen" onAction="ButtonPressedMsgBox"/>
<button id="button2C" label="Button H2" imageMso="FileOpen" onAction="ButtonPressedMsgBox"/>
</box>
<box id="box4" boxStyle="horizontal">
<button id="buttonHA" label="Button HA" onAction="ButtonPressedMsgBox"/>
<button id="buttonHB" label="Button HB" onAction="ButtonPressedMsgBox"/>
</box>
<box id="box5" boxStyle="horizontal">
<button id="buttonHZ" label="Button HZ" onAction="ButtonPressedMsgBox"/>
<button id="buttonHX" label="Button HX" onAction="ButtonPressedMsgBox"/>
</box>
</group>
<group id="Group4" label="Gallery">
<gallery id="Gallery1" label="Pictures" imageMso="HeaderFooterPictureInsert"
screentip="What have we here?" onAction="ClickImage" columns="2" rows="3"
itemWidth="150" showItemLabel="false" itemHeight="150" size="large">
<item id="pic1" image="pic1" label="Picture 1" screentip="This is picture1" />
<item id="pic2" image="pic2" label="Picture 2" screentip="This is picture2" />
<item id="pic3" image="pic3" label="Picture 3" screentip="This is picture3" />
<item id="pic4" image="pic4" label="Picture 4" screentip="This is picture4" />
<item id="pic5" image="pic5" label="Picture 5" screentip="This is picture5" />
<item id="pic6" image="pic6" label="Picture 6" screentip="This is picture6" />
<!--Buttons at bittom of gallery menu-->
<button id="galleryMenuButton1" label="Fetch pictures..." imageMso="PictureInsertFromFile"
onAction="FetchPictures"/>
<button id="galleryMenuButton2" label="Become an MVP..." image="mvp"
onAction="BecomeMVP"/>
</gallery>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
We can add a dialogLauncher to the group that contains this gallery control now. IT MUST BE THE LAST CONTROL IN THE GROUP! It must also of course have a button to create the action required. The additional code is below (just the gallery control part with it added) and the resultant control in the corner of the group (with the cursor next to it).
<group id="Group3" label="Gallery">
<gallery id="Gallery1" label="Pictures" imageMso="HeaderFooterPictureInsert"
screentip="What have we here?" onAction="ClickImage" columns="2" rows="3"
itemWidth="150" showItemLabel="false" itemHeight="150" size="large">
<item id="pic1" image="pic1" label="Picture 1" screentip="This is picture1" />
<item id="pic2" image="pic2" label="Picture 2" screentip="This is picture2" />
<item id="pic3" image="pic3" label="Picture 3" screentip="This is picture3" />
<item id="pic4" image="pic4" label="Picture 4" screentip="This is picture4" />
<item id="pic5" image="pic5" label="Picture 5" screentip="This is picture5" />
<item id="pic6" image="pic6" label="Picture 6" screentip="This is picture6" />
<!--Buttons at bittom of gallery menu-->
<button id="galleryMenuButton1" label="Fetch pictures..." imageMso="PictureInsertFromFile" onAction="FetchPictures"/>
<button id="galleryMenuButton2" label="Become an MVP..." image="mvp" onAction="BecomeMVP"/>
</gallery>
<!--This group has a dialogBoxLauncher and button control which adds-->
<!--the little arrow on bottom right of group Make it last control element in group-->
<dialogBoxLauncher>
<button id="myLauncher" label="Dialog Launcher" screentip="This is a screentip" supertip="This is a supertip"
onAction="LaunchDialog" />
<!--The dialogBoxLauncher is a container control-->
<!--It needs a button control to add an onAction attribute-->
</dialogBoxLauncher>
</group>

That's going to be all for this part, in the final part we will explore the remaining popular controls, take a little more look at the callback signatures and attempt to invalidate the ribbon and change controls on the fly. Hopefully you're enjoying it...stay tuned!
Posted
Feb 14 2008, 11:56 PM
by
Nick Hodge