Automatically execute some code after the UserForm is drawn - vba

I have created a UserForm where the user is required to fill-in three fields. The macro attempts to auto-detect these fields' values in the UserForm_Initialize() event, then displays the found values in the three fields, but the user can change them. The auto-detection takes a few seconds, though, and delays the appearance of the UserForm. I'd like the UserForm to appear with its fields blank before the auto-detection procedure, then have the auto-detection procedure fill the fields automatically. What would be the best way to do this? Making the UserForm non-modal makes the macro run without waiting for the user's input, which is problematic. I don't want to have an "auto-detect" button: this has to be done automatically.

Use the Activate() event instead of Initialize() :)
Private Sub UserForm_Activate()
End Sub
FOLLOWUP
Thanks! It works, but there seems to be a bug: the dialog is drawn all white until the macro completes. screenshot (the dialog should be gray)
No. It is not a bug :) Try This. Add Doevents as shown below.
Private Sub UserForm_Activate()
UserForm1.ProgressBar1.Value = 0
starttime = Timer
While Timer - starttime < 1
UserForm1.ProgressBar1.Value = (Timer - starttime) * 100
DoEvents
Wend
End Sub
HTH
Sid

There is a simpler way to do this...
1) On your userform create a new 'CommandButton' that will execute the macro you wish to trigger.
2) Set the height and the width of the button to 0
3) Make sure the 'TabIndex' parameter for the button is 0... This will create an 'invisible' CommandButton that will receive the focus as soon as the form opens.
4) In the calling routine, immediately before the command that 'shows' the userform enter the line - 'Application.SendKeys "~"'
How it works...
The commandbutton created in (1) is a valid control just like any other wxcept that you can't see it or click it with the mousebutton. The 'SendKeys' command replicates a left mouse key click which is stored in the keyboard buffer until the form displays when it will be read. This has exactly the same effect as a mouse click and will run the required macro.
Incidentally, if you are calling the macro from more than one location and wish to have different actions dependant on the source of the call, you can add more than one 'invisible' button and add "{Tab}" before the "~" character to tab the focus through the available controls. e.g. 'Application.SendKeys "{Tab}~"' will activate the button with the 'TabIndex' parameter set as 1. 'Application.SendKeys "{Tab}{Tab}{Tab}{Tab}~" ' will activate the button with the 'TabIndex' parameter set as 4 etc.
RF

I'd suggest using a timer. Open the form with the input fields disabled and empty, and set the timer to fire within a couple of hundred milliseconds. This should allow the form to be displayed immediately. Do your auto-detection within the timer's tick event (disable the timer first), then enable the fields and fill in the detected values.

Related

Get value from command button VBA

I have created A userform with few command buttons.
I can't seem to figure out how do I get the information from them.
I want to open this userform from another one and then I want the user to choose an option from one of the buttons which will change a specific cell in the table itself
the userform I created
I did not write anything on this userform therefor there is no code from it to show only the design.
how do get the information from the buttons to be written in A specific cell on a specific worksheet?
double click on one of the buttons, in the code menu a new sub should appear. this looks something like:
Sub CommandButton1_onClick()
End sub
Alongside this event method, it also has a few properties. The one that is usefull here is the CommandButton1.Value, this represents the state of the button (either true or false iirc).
So build for each button (I strongly advice giving them custom names to prevent getting lost in the trouble) as sub like this:
Sub CommandButton1_onClick()
if CommandButton1.Value then
ThisWorkBook.WorkSheets("WorksheetName").Range("YourRange").Value = "Some value"
else
ThisWorkBook.WorkSheets("WorksheetName").Range("YourRange").Value = ""
end if
End sub

In a VBA Userform, which event is triggered when exiting a filed

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.

Ellipsis Textbox for VBA Userform File Select

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.

Disable running macros from the "View Macro" screen until VBA project password is entered?

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)

Microsoft Word VBA tab key to make textbox visible

Longtime viewer, first time question asker.
I'm currently working with UserForms within MS Word and have a particular form that can have up to 20 different labels and accompanying textboxes with varying texts. I have all but the first hidden while not in use, however I would like the next label and text box to become visible following input in the previous textbox. So if you enter data (anything) in the first textbox, the next label and text box will become visible. Does this make sense? I've seen other responses here suggest using AfterUpdate() rather than Change() or Click() but can't figure out how to use any of them. I would share my code but at this point I don't have any code to share, other than my labels and textboxes are lblField1 txtField1, lblField2 txtField2...
Any suggestions?
I would suggest using Change event, when using AfterUpdate you need to leave you TextBox for a while to fire the event. If you have only one TextBox visible there is nothing to move to. If you have more TextBoxes you would need to move back to fire AfterEvent and I don't think this is what you expect.
So, double click wherever on your userform and add the following code in code area:
Private Sub txtField1_Change()
txtField2.Visible = True
lblField2.Visible = True
End Sub
Next, add next portion for next textbox:
Private Sub txtField2_Change()
txtField3.Visible = True
lblField3.Visible = True
End Sub
And so on, if only you have an order in controls name you just need to change numbers in the end of control names.