I've seen lots of code for how to ActivateTab OnLoad but can't get it to work dynamically... on the click of a worksheet button for example.
There is a button on Sheet1 pointing at startHereConfigure
<customUI onLoad="RibbonOnLoad"
xmlns="http://schemas.microsoft.com/office/2009/07/customui">
Public Rib As IRibbonUI
Sub RibbonOnLoad(ribbon As IRibbonUI)
Set Rib = ribbon
End Sub
Sub startHereConfigure()
Rib.ActivateTab "Configure"
End Sub
I want to be able to call startHereConfigure (and other similar subs) to bring to the fore a particular Tab - how do I do this?
Add this line to the custom XML file:
<customUI onLoad="RibbonOnLoad" xmlns="http://schemas.microsoft.com/office/2009/07/customui">
Where "RibbonOnLoad" is the name of the function to be called upon starting Outlook.
Add this funciotn into a standard module:
Public Rib As IRibbonUI
Sub RibbonOnLoad(ribbon As IRibbonUI)
Set Rib = ribbon
Rib.ActivateTab "Configure" ' Name of the tab to activate
End Sub
Jorge's answer is the normal way.
I introduce 2 other work-arounds here.
One is moving your custom tab control before the Home Tab
by adding 'insertBeforeMso' in your customui(14).XML.
<tab id="id1" label="Tab1" insertBeforeMso="TabHome">
Your 'Tab1' is the first one, so it is activated first when opening your office file.
The other one is using SendKey method which is a little tricky.
After adding onLoad macro in customui XML,
you can add following lines in a module in VBE.
Sub onLoad(control As IRibbonUI)
'control.ActivateTab "Tab1"
Application.SendKeys "%Y%" 'Alt + Y + Alt key
End Sub
Here 'Y' key is your custom tab shortcut key and 'Alt' key is sent again after 'Y' key in order to prevent the Alt shortcut keys from appearing on ribbon menus.
Samuel Liew: I thought the way I answered was implicit enough.
The following is the same expanded to be more explicit:
Sean: Unclear from the above if you got an answer or you solved it yourself.
As, I can't see an answer and your last comment suggests you went off with false information.
Certainly your code should work in 2010 office systems.
I'm doing just that and activating a range of different tabs, based on targeted worksheet 'types' becoming active. And the tab activation code is just part of a general workbook events handling sub (i.e. called by application event handlers).
And that has been operational since prior to you asking this question.
So the response from Siddharth Rout above about not being able to do this is invalid.
I'm assuming your Tab id is defined in the xml to match the id in your code above per:
<tab id="Configure" label="YOUR LABEL" >
I'm also assuming the rest of your xml is correct, and you can see the tab, just not be able to activate it.
If all that's the case, as to 'How to': You should just need to call that sub.
In my case I do that on Workbook or Worksheet activated (on open or change of window). But any call mechanic (such as your in-sheet control) should work just as well.
As an aside, I'd recommend using more obviously unique codes for ribbon control ids
e.g. Using some leading chars from the overall function and the control type like 'xyzTab_Configure'.
Just means if/when you add more, you have a explicit way to know which is which, and avoid any clashes.
That all covered: I have however run into an issue with office 2019.
See: vba IRibbonUI.ActivateTab not working in Office 2019
Related
(Be kind to me; I'm not a professional developer!)
I've created a custom Word ribbon with all sorts of business-specific functionality. I think it's awesome, but there are some old-school people here who want the built-in "Home" tab to show up by default because that's what they're "used to."
I added a menu option to change the default between the Home Tab and the HMF tab. The problem is that I can't actually figure out how to use the setting to change the active tab.
Here's a snippet of the ribbon code:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="HMFRibbon.InitializeRibbon">
<ribbon>
<tabs>
<tab id="HMFTab" label="HMF" insertAfterQ="TabHome">
[...]
</tab>
</tabs>
</ribbon>
</customUI>
My STARTUP folder contains an "HMF_Toolbar.dotm" that includes the following code in the "HMFRibbon" module:
Public ribRibbon As IRibbonUI
Sub InitializeRibbon(ribbon As IRibbonUI)
On Error GoTo DefaultError
If GetSetting("HMFToolbar", "Defaults", "HMFIsDefault") = "False" Then
MsgBox ("Leaving 'Home' as default tab")
Else
Set ribRibbon = ribbon
MsgBox ("Activating 'HMFTab'")
ribRibbon.ActivateTab ("HMFTab")
End If
Exit Sub
DefaultError:
MsgBox ("Could not find default toolbar setting.")
End Sub
The code runs the first time a document is open, finds the right default and shows the right message, but doesn't actually change the starting tab to HMFTab. It also only runs when the ribbon is first opened, so even if it worked the first time it wouldn't run when subsequent documents were open (would would again default to "Home").
I tried moving the function to "AutoOpen()" in the HMFRibbon module, but that only fires if I open "HMFRibbon.dotm," not another document with the module loaded.
So... any ideas?
EDIT: I should have been clearer. By "default tab," what I really mean is that I want the ribbon to automatically activate either the "Home" or "HMF" tab depending on whether HMFIsDefault is true or false.
I've gotten closer by using the Application.AutoOpen function, but it fires before the ribbon is actually loaded, so "active doesn't work! Here's the code:
Option Explicit
Public WithEvents oApp As Word.Application
Private Sub oApp_DocumentOpen(ByVal Doc As Document)
On Error GoTo DefaultError
If GetSetting("HMFToolbar", "Defaults", "HMFIsDefault") = "False" Then
MsgBox ("Leaving 'Home' as default tab")
Else
MsgBox ("Activating 'HMFTab'")
HMFRibbon.ribRibbon.ActivateTab ("HMFTab")
End If
Exit Sub
DefaultError:
MsgBox ("Could not find default toolbar setting.")
End Sub
The IRibbonUI.ActivateTab method can be used for activating ribbon tabs. You just need to pass the Id of the custom Ribbon tab to be activated. You may also find the IRibbonUI.ActivateTabMso method for built controls and IRibbonUI.ActivateTabQ which uses the fully qualified name of the tab, which includes the ID and the namespace of the tab.
You may consider using the insertAfterMso attribute for the custom ribbon tab if you want to place it after a specific built-in ribbon tab.
Compare the following attributes:
insertAfterMso - Specifies the identifier for the built-in control after which to position this control.
insertAfterQ - Specifies the identifier of a qualified control (that is, a control whose idQ property was specified) after which to position this control.
Read more about the Fluent UI (aka Ribbon UI) in the following series of articles:
Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3)
Customizing the 2007 Office Fluent Ribbon for Developers (Part 3 of 3)
I'm using Microsoft Office Professional Plus (64 bit) on a Windows 10 (64 bit) platform. I have a subroutine that is processed when I make a change to a Userform field called MyDate. It's called Private Sub MyDate_AfterUpdate(). It's the second field on a form. It works fine as long as the contents of the MyDate field are edited. However, if the user doesn't need to update the contents of the MyDate field because they accept the default of the field and just presses the tab key past that second field, I'd still like the subroutine to be executed. What event can I use to activate code when I simply tab through the field and don't necessarily edit the contents? Thanks for looking at this.
If you look at the top of the code panes, you'll notice two dropdowns. The left one contains all interfaces and event providers you can implement in that class (a UserForm is a class).
Select your MyDate control from that dropdown; the right-side dropdown is now listing every event you could handle for this MyDate control:
In this particular case, the Exit event seems a good candidate:
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
'make Cancel.Value = True to prevent exiting the control.
'...ideally... make that conditional...
End Sub
By consistently using these dropdowns to let the VBE generate event handler procedures for you (instead of typing them up from memory), you avoid getting it wrong... and getting an event handler signature wrong can do anything from literally nothing at all, to compile errors if you're lucky, or weird and hard-to-diagnose behavior if you're less lucky.
I am trying to create a path selection user interface for an extensive VBA program I've been working on, but I can't seem to get the ellipsis textbox that I'd like. This is a very common feature, especially in option tables. This is an example of what I'd like to get, straight from the VBA Options panel:
I would LOVE to find a way to get the same functionality in a Userform. The only solution that I've found thus far is to use a combo box with the ellipsis arrow option enabled. However, there doesn't seem to be an apparent way to use the activation of the combo box arrow to run a dialog box, nor does there seem to be a way to make it look UNLIKE a combo box. Last resort I use a button below the text box, but I'd really prefer a less-bulky way of doing this.
Any solution would be greatly appreciated.
The only solution that I've found thus far is to use a combo box with
the ellipsis arrow option enabled. However, there doesn't seem to be
an apparent way to use the activation of the combo box arrow to run a
dialog box, nor does there seem to be a way to make it look UNLIKE a
combo box
Your suggestion does work, and it is surely less complex and more elegant than having two controls work together, Button + Textbox.
A Combo can achieve perfectly the desired feature, in the following way.
1) In design mode, set the button style to Ellipsis
DropButtonStyle = fmDropButtonStyleEllipsis
And eventually, make the ellipsis show up only when the combo is entered, by setting the design-time property:
ShowDropButtonWhen = ShowDropButtonWhenFocus
2) If needed, you can set other design-time properties to have some look and feel. The defaults look pretty good however.
3) Add the following handler to the parent userform. The snippet simulates the launching of a dialog and getting a new value or cancelling. It does not show any dropdown window. (but you still have control over that: if you want to show it according to some condition, you still can call the method ComboBox1.DropDown)
Private Sub ComboBox1_DropButtonClick()
' The following two lines avoid to call the routine twice, at entry and at exit
Static i As Integer
i = (i + 1) Mod 2: If i = 0 Then Exit Sub
With ComboBox1
s = InputBox("enter some text", , .Value) '<~~ simulates any dialog
If s <> "" Then .Value = s
SendKeys ("{Enter}") '<~~ to close immediately the dropdown window
End With
End Sub
Try it ;)
Not only do ComboBoxes have Drop Buttons, so do TextBoxes (as do Excel's RefEdit controls). Even though you can't access the Textbox's Drop Button at design time, you can do so at runtime. Using a textbox avoids having to deal with the dropped down list of a combobox.
Given a textbox named TextBox1, the following code will provide the desired ellipsis drop button:
Private Sub UserForm_Initialize()
With Me.TextBox1
.DropButtonStyle = fmDropButtonStyleEllipsis
.ShowDropButtonWhen = fmShowDropButtonWhenAlways
End With
End Sub
Then use the DropButtonClick event of the textbox to perform whatever action you want:
Private Sub TextBox1_DropButtonClick()
'' Code here to do what you need
End Sub
I have an extensive example at Alternative to Excel’s Flaky RefEdit Control that uses a textbox with a "Reduce" drop button to replicate the functionality of Excel's unreliable RefEdit controls.
From the Excel Window, I can assign a shortcut key to my macro by:
going to the Developer tab
touching the Macros button
touching Options... in the resulting Dialog Box
Can I assign this from within the VBE Window, using the VBE menu bar instead??
The Application.OnKey approach keeps the shortcut separate from the procedure (which makes maintenance difficult), and you might end up with conflicts - particularly if you've assigned keys using the Macros dialog and the Application.OnKey property. And, of course, you need the SetShortCutKeys code to run on workbook_open, which might not always run.
Fortunately, it is possible to assign the shortcut key in VBA, and within the procedure itself, but you'll need to export the module, edit the text file, and then reimport. Unfortunately, while VBA does maintain the code, the shortcut keys only seem to work in Excel. Perhaps it's a feature of VBA that the host application can optionally support.
Let's say you have the following VBA in a standard module:
Option Explicit
Public Sub Bar()
MsgBox "Bar"
End Sub
If you use the Macros dialog in Excel, and choose a shortcut key for the Bar macro to Ctrl+Shift+T, and then Export the module to a text file, you'll find the module source is:
Attribute VB_Name = "Module1"
Option Explicit
Sub Bar()
Attribute Bar.VB_ProcData.VB_Invoke_Func = "T\n14"
MsgBox "Bar"
End Sub
Notice the Attribute Bar.VB_ProcData.VB_Invoke_Func = "T\n14" attribute, which wasn't visible in the VBIDE, but is persisted by VBA in the underlying source. The T in T\n14 is a case-sensitive key (which implies a Shift), and I think the \n14 must refer to the Ctrl key. By following the VB Attribute naming pattern and syntax, and including similar lines in your other procedures, you can assign shortcut keys in other procedures using the text editor, and then, when you're done, you can import the modified module back into the VBA project.
Note that once you import the modified module, you'll no longer be able to see the attribute lines, and you'll need to take care not to change the name or number of parameters in the procedure, as the VBIDE might delete the underlying attribute without warning you.
Alternatively, if you want to do it using VBA you can do something like:
Sub SetShortcutKeys()
With Application
.OnKey Key:="^+K", Procedure:="YourMacroGoesHere"
End With
End Sub
So first, when one clicks on the "View Macro" button, this pops up:
What I want to know is, is there some code that I can run on workbook open (and then "unrun" on workbook close) that grays out that run button (like the others underneath it are) ONLY until the password is entered in the VBA project (using Alt+F11 to open the editor)?
I don't want the users to be able to run any of these subs manually.
If you declare the sub so that it needs input, even optional input it will not show in the list either.
sub Test(optional a as string)
Declare the subs as private and they won't show up in the Alt+F8 dialog box.
Declare them as public (the default) and they will.
You can use vba to edit the vba code of another module.
Is it possible in Excel VBA to change the source code of Module in another Module
You can change one line or search through the lines and comment/uncomment whole blocks of code. Capturing the event when vba is unlocked may be the hard part. You may have to run a sub that does this after unlocking vba.
I think you have the wrong approach to this and it would be better to structure your code more properly.
The first two on that sheet are called from other macros that are run with buttons on my main worksheet.
OK. So attach these to a form control/button, and use Bigtree's suggestion to include an optional argument in these subs. They will not display in the Macros menu. YOU can run them at least three different ways:
either from the VBE by finding the procedure and pressing F5, or
by entering the name of the procedure in the Immediate window in the VBE, or
by pressing the buttons you have provided.
The middle two are called when the sheet opens and closes
Sounds like this should be a private subroutine (or, use the method above from Bigtree) and CALL these from the one or more of the appropriate event handlers (at the worksheet level perhaps: Worksheet_Activate, Worksheet_Deactivate; or at the workbook level SheetActivate and SheetDeactivate depending on your needs)
You can always run the procedure manually from the Immediate window in VBE, or by manually invoking the event procedure, etc.
and the last two I manually call when I want to edit my main sheet
Again, call from the Immediate window or manually from the VBE. You only have 6 subroutines here, it can't be that difficult to locate the ones you frequently need. Put them in a new module and organize your modules so you know where these are.
Alternatively, put some boolean in the subroutine like:
Sub SheetLock()
If Not Environ("username") = "YOUR_USERNAME" Then Exit Sub
'other code to do stuff is below...
End Sub
UPDATE FROM COMMENTS
The Immediate Window is like a console/command line, it is where the result of your Debug.Print statements would appear, etc. It is very handy for debugging and evaluating expressions.
There are several ways you could invoke the subroutine depending on whether it is public/private, including
Application.Run "MacroName" or simply MacroName if public
Application.Run "ModuleName.MacroName" or Call ModuleName.MacroName if private
I did not want to use a private sub,
I used the shape name to determine if from a button
On Error GoTo noshapeselected
shapeis = ActiveSheet.Shapes(Application.Caller).Name
' I manually set the shape name in the page layout tab selection pane
' below I test for the desired button
If shapeis = "your button name" then
goto oktogo
else
goto noshapeselected
endif
noshapeselected:
msgbox ("must run from a button")
goto theendsub
oktogo: 'continue if desired shape was selected
theendsub: 'a button was not pushed
For those macros without buttons, but called by another macro,
set a variable to 'OK' to run a macro, then the called macro tests for 'OK' ('OK' means initiated by another macro 'NOK' means not initiated by another macro)