So I have an excel workbook that opens userform1 on the workbook open event.
Once certain conditions are met on userform1 it calls a procedure that loads and shows userform2. Userform2 has a label, a textbox and a button. This issue I have is that the events for the textbox on userform2 don't all fire correctly. The KeyUp & KeyDown events fire as expected, but the Change and AfterUpdate event never get called.
I've been able to replicate the behavior in another workbook that is greatly simplified. If you key or paste a text string longer than 7 characters in the textbox on userform1 it loads userform2. The desired behavior is to key in a 3 digit numeric value in the textbox on userform2 and call a sub from userform1. This never happens. Has anyone else seen this behavior before? How did you work around it?
USERFORM1: (excuse the Ascii art, evidently I don't have enough reputation to post images) :/
Label1: [ Textbox1 ]
Label2:
[ CommandButton1 ]
Option Explicit
Private Sub CommandButton1_Click()
Unload Me
End Sub
Private Sub TextBox1_Change()
If Me.TextBox1.TextLength >= 7 Then
Load UserForm2
UserForm2.Label1.Caption = "Value for " & Me.TextBox1.Text & "?"
UserForm2.Show
End If
End Sub
Public Sub Form2(data As Variant)
On Error GoTo eh
Me.Label2.Caption = Me.Label2.Caption & vbCrLf & Me.TextBox1.Text & vbTab & CStr(CLng(data))
eh:
If Err.Number = 13 Then
MsgBox "Please input a #"
UserForm2.TextBox1.SetFocus
ElseIf Err.Number = 0 Then
Unload UserForm2
End If
End Sub
USERFORM2:
label1: [ Textbox1 ]
[ CommandButton1 ]
Option Explicit
Private Sub CommandButton1_Click()
Call UserForm1.Form2(Me.TextBox1.Text)
End Sub
Private Sub TextBox1_Change()
'This event never fires
If Me.TextBox1.TextLength >= 3 Then
Call UserForm1.Form2(Me.TextBox1.Text)
Else
Debug.Print "here"
End If
End Sub
Private Sub TextBox1_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
'This event fires
Debug.Print KeyCode
End Sub
I am not sure why this happens as you can run userform2 by itself and it works. However to get around this to start with it might be best to put the code in keyUp event. That should work
EDIT
I have found a slight work around. It is not perfect as I cannot find out why it is not firing. However the up and down key press works fine. I have added this code and now the event should fire. But it is a semi-manual event.
Private Sub TextBox2_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Call TextBox2_Change
End Sub
So when a key is pressed down. It will check for any changes.
I ended up making use of the KeyUp and BeforeDropOrPaste.
Sam, thanks for the inspiration. I was trying to replicate the code of the Change event into the actual procedure. I ended up calling the event directly from the KeyUp procedure and using Application.OnTime "UserForm2.TextBox1_Change" in the BeforeDropOrPaste event to get around the missing data.
The problem is that your code is showing the 2nd userform modally. In this situation, the TextBox1_Change() procedure in the 1st form is not allowed to complete while the 2nd userform is displayed. This interferes with the event messaging.
To resolve the issue, simply show the 2nd userform modelessly:
UserForm2.Show vbModeless
Please do not resort to the suggested hack.
Excel Hero is correct, the only point is to load a modeless userform next to a modal userform you have to .hide the modal userform so it will not interfere with the modeless userform.
see code below:
Private Sub TextBox1_Change()
If Me.TextBox1.TextLength >= 7 Then
Me.hide
Load UserForm2 vbModeless
UserForm2.Label1.Caption = "Value for " & Me.TextBox1.Text & "?"
UserForm2.Show
End If
End Sub
you can load UserForm2 as vbModeless or make the userform by default modeless.
Related
I want to display Userform2 from Userform1 then continue executing some code in Userform1 WITHOUT unloading Userform1
Private Sub CommandButton1_Click()
UserForm2.Show
x = 1
MsgBox x
End Sub
Not sure that's what you want, but this would do what you describe:
UserForm2.Show vbModeless
Note that UserForm2 isn't modal anymore, which means the user can click outside the form, and even end up hiding it behind UserForm1.
Modal forms return execution to the caller when they're hidden/closed or destroyed, modeless forms return execution to the caller immediately (Initialize and Activate handlers will run first though).
Assuming you mean without unloading Userform2...
Userform1 will wait for Userform2 to finish... however you can do something like this:
Userform1:
Private Sub CommandButton1_Click()
UserForm2.Show
End Sub
Sub uf1msgbox()
X = 1
MsgBox X
End Sub
Userform2:
Private Sub CommandButton1_Click()
UserForm1.uf1msgbox
End Sub
I have 2 userforms, Userform_1 contains many TextBoxes (TextBox1, TextBox2, TextBox3, .....) & in Userform_2 I have 1 TextBox where user can enter value. Now I need to pass the User entered value in Userform_2 to be shown/stored in its respective triggering TextBox event in Userform_1. So when User want to pass in TextBox3 (Userform_1) then he/she will just use double_click trigger (activate Userform_2) & pass value which should be stored in TextBox3 only.
I tried this:
In Userform_1
Private Sub TextBox3_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
On Error Resume Next
UserForm2.Show
End Sub
In Userform_2
Private Sub CommandButton1_Click()
On Error Resume Next
If UserForm1.TextBox1.Value = "" Then UserForm1.TextBox1.Value = ComboBox1.Value
If UserForm1.TextBox2.Value = "" Then UserForm1.TextBox2.Value = ComboBox1.Value
If UserForm1.TextBox3.Value = "" Then UserForm1.TextBox3.Value = ComboBox1.Value
Unload Me
End Sub
Problem is that it will display entered value in any TextBox which is empty & not specifically in TextBox3. Any insight would be helpful.
Your code is doing exactly what you have asked it to do (not what you want it to do). Based on your description above, I offer the following (not tested).
In Userform_1
Private Sub TextBox3_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
UserForm2.Show
TextBox3.Value = UserForm2.ComboBox1.Value
End Sub
In Userform_2
Private Sub CommandButton1_Click()
Me.Hide
'Note not unloading, this means that the userform is still in memory and you can access the values after it is hidden.
' Also, hiding the form will return control back to the UserForm1 for further processing.
End Sub
And avoid using On Error, especially On Error Resume Next, all you are doing is hiding the bugs, not dealing with them. If you can anticipate that your code is going to cause an error, deal with it before that piece of code.
Thanks ADJ...
Your concept is good but it doesn't quite fulfill the requirement, just hiding the Userform doesn't remove/clear the entered value for next entry & reopening it again shows last entered value. I can write a code to blank it but then I have too many textboxes.
I used your concept of only calling required Userform from a specific TextBox...
Wrote below code, fits my requirement:
UserForm_1:
created hidden TextBox1 in UserForm_2 for identifier
UserForm2.TextBox1.Value = "<random identifier value>"
UserForm_2:
If TextBox1.Value = "<random identifier value>" Then
UserForm1.TextBox3.Value = "<User Input>"
End If
So this way I get to assign & call only identified TextBoxes.
I have a sub called as sub1() which activates the userform1 through the command userform1.show()
This userform1 has a button called as continue. On clicking that button continue - A Macro called as Private Sub continuebutton() gets activated.
I want to program in such a way that it redirects to the line after userform1.show() in sub1().
Is it something that can be done?
Theoretically, what you want is possible, if you do it like this:
In the UserForm:
Private Sub btnContinue_Click()
flag = True
Debug.Print "I continue ..."
sub1
End Sub
In a module:
Public flag As Boolean
Public Sub sub1()
If flag Then
Debug.Print "sub 1 continues here..."
Else
flag = False
UserForm1.Show
Exit Sub
End If
End Sub
It will work exactly as intended, BUT it is not a good practice to work this way. (Some people may throw stones at you for using public variables at all in VBA.) Here are two articles, that give better ideas:
https://rubberduckvba.wordpress.com/2017/10/25/userform1-show/
Disclaimer - this one is mine:
http://www.vitoshacademy.com/vba-the-perfect-userform-in-vba/
On the form properties for userform1, set its "Modal" property to true.
When the form opens, it will have exclusive focus, and the code in sub1 will not continue running until after it closes. This may be the solution you need.
In the code below, the msgbox will only appear once userform1 closes:
sub sub1()
userform1.show()
msgbox "Now continuing with sub1"
end sub
No way as long as you show the form.
If you show the form modal, the calling routine continues if (and only if) the form is closed.
If you show the form non-modal, the code continues to run directly after the show - so it's already done.
So either you have to close the form when the user clicks the "continue..." button to let the calling macro continue or you have to split your code into two routines and call the second on button-click.
You can change your Sub1 as follows:
Sub sub1(Optional Continue As Boolean)
If Continue = True Then
DoSomeStuff
Exit Sub
End If
userform1.show
End sub
And then, you can call your sub1 using:
Private Sub continuebutton()
Call sub1(True)
End Sub
Hope it helps
If you don't want to go with the 'Modal Form' solution, you could add a subroutine to your main module, and call it when required. So, in userform1, you have:
sub sub1()
userform1.show()
end sub
public sub sub2()
msgbox "Now continuing..."
end sub
And then in userform1, set some code on its onClose event:
Private Sub continuebutton()
Call sub2()
end sub
I need to enter multiple characters into an ActiveX textbox in PowerPoint before the marco fires. Current macro fires as each character is typed.
Private Sub TextBox1_Change()
IF TextBox1.Value = "18" then
MsgBox "You have entered 18"
End If
End Sub
Previous attempts had failed so I had to add a CommandButton that would trigger the actions after all the characters were typed in the text box, however it is cumbersome to type and click to perform tasks. So it would be even better if the Macro would be triggered after hitting the Enter/Return key after the data required was entered. I have tried KeyPress and KeyDown and i.e.
Private Sub TextBox1_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyReturn Then
MsgBox "hello"
End If
End Sub
but that code gave me a compile error:
Procedure declaration does not match description of event or procedure having the same name.
Perhaps the LostFocus event would be more useful. Assuming that TextBox1 is on Slide 1:
Private Sub TextBox1_LostFocus()
MsgBox ActivePresentation.Slides(1).Shapes("TextBox1").OLEFormat.Object.Text
End Sub
I have created a userform that has two buttons on it. One is called CmdCon6 and the other is called CmdLbs6. When clicked, they are suppose to close the current userform, pull up another userform, and pull values from the 4th column in sheet18 and add them to a combobox named x48 (both of the new userforms have a combobox named x48)in the new userform. The range of cell values to be added to the combobox x48 will flucuate, but never exceed 20 (hence why I added a loop). Everything works great and does what it is suppose to do when I click the CmdCon6 button, but when I click the CmdLbs button, it gives me a run-time error '70' Permission denied and highlights the 20th line of code (line between the If and end if in the Sub CmdLbs_Click()).
I have tried to change the name of the combobox x48 in the frmInputLbs6 userform and keep it as x48 for the frmInputCon6 userform, but I still received the same error.
Any suggestions to fix this issue? I'm stumped, and can't think of a way around it. Thanks in advance!
Private Sub CmdCon6_Click()
Unload Me
For x = 1 To 20
If Sheet18.Cells(x, 4).Value <> "" Then
frmInputCon6.x48.AddItem Sheet18.Cells(x, 4)
End If
Next x
frmInputCon6.Show
End Sub
Private Sub CmdLbs6_Click()
Unload Me
For x = 1 To 20
If Sheet18.Cells(x, 4).Value <> "" Then
frmInputLbs6.x48.AddItem Sheet18.Cells(x, 4)
End If
Next x
frmInputLbs6.Show
End Sub
Controls on UserForms are private by default. You need to access them through the Controls collection:
Private Sub CmdLbs6_Click()
Unload Me
For x = 1 To 20
If Sheet18.Cells(x, 4).Value <> "" Then
frmInputLbs6.Controls("x48").AddItem Sheet18.Cells(x, 4)
End If
Next x
frmInputLbs6.Show
End Sub
I'd also note that although you mention that "they are suppose to close the current userform", this isn't what happens. Your forms also aren't actually being fully unloaded until the other form is closed. The .Show method defaults to modal so in the code above frmInputCon6 doesn't fully unload until after frmInputLbs6 is closed.
Just something to keep in mind, because it really messes up your event stack. You can see the results by with this simple test code. Add UserForm1 and UserForm2, and put a button on each of them and the following code:
UserForm1:
Private Sub CommandButton1_Click()
Unload Me
UserForm2.Show
End Sub '<--Put a breakpoint here.
Private Sub UserForm_Terminate()
Debug.Print "UserForm1 closed"
End Sub
UserForm2:
Private Sub CommandButton1_Click()
Unload Me
UserForm1.Show
End Sub '<--Put a breakpoint here.
Private Sub UserForm_Terminate()
Debug.Print "UserForm2 closed"
End Sub
Put a breakpoint on the End Subs of each Click() event, fire up one of the forms and hit the buttons to hop back and forth a few times. Then close one of the forms and count how many times you hit the breakpoints before you actually exit.