Getting contents of textbox in custom form - vba

Currently I've attached a function to a command button on my form which retrieves what the user inputs into the textbox on the form; this works fine but I want to emulate this behaviour with the ENTER key. How can I go about doing this?
I tried the Enter Property on the textbox but that only occurs when focus has been transfered to the textbox, not when i press enter after input.
I've read about the KeyUp event for VB but there's got to be an easier way - I've googled this but can't find what Im looking for. Any suggestions?
Thanks

In many cases, the After Update event is suitable for working with data entered into a textbox, for example:
Private Sub txtFilter_AfterUpdate()
Me.Filter = "Content " & Me.txtFilter.Text
Me.FilterOn = True
End Sub
However, if you need to edit or validate the data, Before Update is more suitable.
Private Sub txtText_BeforeUpdate(Cancel As Integer)
If Me.txtText = "Invalid" Then
Me.Undo
Cancel = True
End If
End Sub

Related

Send keystroke to caret

I have an onscreen number pad 0-9, I'm trying to send a keystroke to a checkbox when a user clicks the button of that number (essentially a touchscreen keyboard). There are several textbox's and I want to send it to the one that currently has the caret in it. I've tried SendKeys.Send("1") but that doesn't send it. What is the best way of doing this?
The issue you are encountering is because when the user clicks on any of your buttons, the button takes focus and the textbox loses focus, and therefore any keystrokes are sent to the control with focus, i.e. the button.
One possible way around this might be to use a global variable to store a reference to the last textbox to have lost focus on the form (via the On Exit or On Lost Focus events of each textbox), and then populate the content of this stored textbox with an appropriate value as part of the On Click event of each button.
A very simple example of this might be something along the lines of:
Dim LastTextBox As TextBox
Private Sub TextBox1_Exit(Cancel As Integer)
Set LastTextBox = TextBox1
End Sub
Private Sub TextBox2_Exit(Cancel As Integer)
Set LastTextBox = TextBox2
End Sub
Private Sub Button1_Click()
If Not LastTextBox Is Nothing Then LastTextBox = "1"
End Sub
Private Sub Button2_Click()
If Not LastTextBox Is Nothing Then LastTextBox = "2"
End Sub

Excel - Change BackColor of UserForm TextBoxes and ComboBoxes with VBA

I am just learning VBA and have used some code from an older book (Excel 2010). It could be that Excel 2016 had some changes that make this code not work anymore.
I do not get a compile error for the class or the Subs. The behavior is that NOTHING happens. What is supposed to happen is that the BackColor of either a ComboBox or a TextBox should change color as if is in focus or leaves focus.
As I said, for some reason when I run the code nothing happens. No errors or warnings appear so it's as if the code is running and then just doing nothing.
Here is my code. The comments should make it clear. I am hoping someone can explain to me what is going on and why this code results in no color changes as the focus changes when I tab through the UserForm.
This first block of code is a stand alone Class Module called "clsCtlColor"
Public Event GetFocus()
Public Event LostFucus(ByVal strCtrl As String)
Private strPreCtr As String
'Base Class for chaging Backcolor of ComBoxes and TextBoxes when focus is changed.
Public Sub CheckActiveCtrl(objForm As MSForms.UserForm)
With objForm
If TypeName(.ActiveControl) = "ComboBox" Or _
TypeName(.ActiveControl) = "TextBox" Then
strPreCtr = .ActiveControl.Name
'On Error GoTo Terminate
Do
DoEvents
If .ActiveControl.Name <> strPreCtr Then
If TypeName(.ActiveControl) = "ComboBox" Or _
TypeName(.ActiveControl) = "TextBox" Then
RaiseEvent LostFucus(strPreCtr)
strPreCtr = .ActiveControl.Name
RaiseEvent GetFocus
End If
End If
Loop
End If
End With
Terminate:
Exit Sub
End Sub
The following Subs are in the UserForm Code
Option Explicit
Private WithEvents objForm As clsCtlColor
'*********************************************************************************************************************
'*Subs for managing the BackColor of comboxes and TextBoxes depending on focus.***************************************
'*********************************************************************************************************************
'initializes the Userform with the clsCtlColor class
Private Sub UserForm_Initialize()
Set objForm = New clsCtlColor
End Sub
'Changes the BackColor of the Active Control when the form is activated.
Private Sub UserForm_Activate()
If TypeName(ActiveControl) = "ComboBox" Or _
TypeName(ActiveControl) = "TextBox" Then
ActiveControl.BackColor = &H99FF33
End If
objForm.CheckActiveCtrl Me
End Sub
'Changes the BackColor of the Active Control when it gets the focus.
Private Sub objForm_GetFocus()
ActiveControl.BackColor = &H99FF33
End Sub
'Changes the BackColor back to white when the control loses focus.
Private Sub objForm_LostFocus(ByVal strCtrl As String)
Me.Controls(strCtrl).BackColor = &HFFFFFF
End Sub
'Clears the objForm when the form is closed.
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Set objForm = Nothing
End Sub
In the Class Module the is an On Error Statement that terminates the Sub when an error occurs. However, I commented it out and still, I see no compile errors. So, I can only conclude it is a runtime issue.
Any help would be much appreciated.
UPDATE:
If I use these two subs on a TextBox I get the effect I'm looking for:
Private Sub TextBox1_Enter()
TextBox1.BackColor = RGB(153, 255, 51)
End Sub
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
TextBox1.BackColor = RGB(255, 255, 255)
End Sub
What I hate about this is that my UserForm has over one hundred TextBoxes and I would need to write these two subs for each TextBox - so like 200++ Subs!
I am still trying to get the above more general approach to work.
One thing I noticed is that if I change the RGB values in the two subs above to Hex values, they no longer work. I tried changing the hex color values in the more general approach to RGB but it made no difference.
Yet Another Update:
It was pointed out that I had a typo in the class LostFucus. I changed that in two places to LostFocus. However, the code still does not work. Then the question was whether or not my code is in the userform module. It is. Then I tried an experiment. I created a new Workbook and imported the code into a brand new class and userform. I added three textboxes. Abracadabra! It worked! However, it does not work in the form I want it to work in. I have scoured the properties for the form itself and the text boxes and I can see nothing different between my form and the dummy form.
This must be something very simple I am over looking!
After a great deal of head scratching and screaming at my poor monitor I finally found the solution but as of now, I am totally disappointed in Microsoft for the weirdness of working with UserForms. Here is what fixed the problem:
I had not yet set the tab order!
I realized the tab order had my form opening with the first tab stop being set for a TextBox in a MultiPage on my form. I set the tab order so that the first TextBox is active on the UserForm and everything works with the coloring on the main body of the form.
Here is where the weirdness begins, in my opinion.
When the last TextBox on the main body of the form is reached and tab is pressed, the multi-page itself is selected. Only after you hit tab a second time is the first TextBox within the MultiPage selected and then the colors are not applied as they are in the main body of the form at all. The same scenario holds true for Frames as well. Also, there does not appear to be a good way to simply tab from the end of page 1 to the beginning of page 2.
It's very disappointing to me because I would have thought that this is not the way it is. I ASSUMED I could set up 1000 TextBoxes, use the Frames and the Multipage to organize things (SO I COULD MAINTAIN THE WINDOW AT ONE SIZE AND NOT HAVE TO SCROLL THE FORM UP AND DOWN) and then set a tab order that would navigate ALL of the TextBoxes regardless of what organizing container they are in. I assumed it would be this way because it MAKES SENSE! I want to click into the first TextBox and simply never touch my mouse until the form is completely filled out. Otherwise, there really is no point in this effort of making a UserForm! I could point and click around in the spreadsheet without the hassle of designing a form and writing code!
What a bummer!
I suppose I can "make it so!" by writing a bunch of code to jump the selection from container to container...MICROSOFT - It should not be this wonky and stupid!

vba userform checking the GroupName instead of an individual button

I'm using a VBA Userform. The MassPrompt userform has a set of six GroupNames and some text boxes. Each GroupName contains two or more radio buttons.
I'd like the following code to be triggered anytime any element within the GroupName "GROnly" changes. If the user made an inappropriate button choice in "GROnly" based on the choice in another group, I'd like to display a warning message and present the MassPrompt userform again.
Right now, I've assigned the code to the one button "GROnly_yes". It works, but only when that one button is clicked. How do I position this within the UserForm code to trigger anytime a button with the GroupName "GROnly" is clicked? Thanks for looking at this.
Private Sub GROnly_yes_Click()
'Prompt if the GROnly is true and it's inappropriate for the GSetting choice
If GROnly_yes = True And GSetting_renewal = True _
Then
GROnly_yes = False
GROnly_no = True
MsgBox ("The GROnly can't be chosen with a Renewal." & vbNewLine & _
"The GROnly button has been changed to 'NO'.")
UserForm_Initialize
End If
'Other IF statements here.
End Sub
If I understood well, GRonly is the GroupBox that contains (let's say) the radio_button_1 and radio_button_2.
The reason why the code doesn't trigger is that when he/she changes the value of one radio-button is not clicking on the GroupBox, but rather changing the value of that single radio-button.
You will have to add the code to the _Change event of the radio button objects. This is an example:
Sub myFunctionalCode()
'your code here
End Sub
Private Sub radio_button_1_Change()
myFunctionalCode
End Sub
Private Sub radio_button_2_Change()
myFunctionalCode
End Sub
Thanks for the reply. That would work.
In the meantime, I came up with another alternative as well. I removed the code from:
Private Sub GROnly_yes_Click()
And I moved it to the button that the user clicks to submit the form:
Private Sub ContinueButton_Click()
In my original code I had to change UserForm_Initialize to Exit Sub to make the code work in the "submit" button.
Thanks again for your help.
Phil

Can you set events within Tab Control for MS Access?

I have been searching the internet for this all day. But no luck.
Can you setup events for when you enter/leave a tab.
I.E.
OnExit(Tab1)
Do something
Thanks
Depending on your program flow, you might try:
Private Sub Combo3_Exit(Cancel As Integer)
If IsNull(Me.Combo3) Then
MsgBox "No exit"
Cancel = True
End If
End Sub
Private Sub Form_Current()
Me.Combo3.SetFocus
''Or to refer to a subform from the main form
Me.subformcontrolname.Form.Combo3.SetFocus
End Sub
Does the tab contain a subform or only controls from the main form?
A subform has an Exit event, so if you are only concerned that once you have entered the subform you should not leave without completing data, you could:
Private Sub subformcontrolname_Exit(Cancel As Integer)
If IsNull(Me.subformcontrolname.Form.Combo3) Then
Me.subformcontrolname.Form.Combo3.SetFocus
MsgBox "No exit"
Cancel = True
End If
End Sub
While this is not exactly what you want, you could instead of handling the exit simply prevent the user from clicking somewhere else. To do this, attach some code to your combobox1 that bascially set .Enabled=Xfor all elements outside your tab view - where X is determined by the state of the combobox...

Closing a bound form without saving changes

Quick question here, hoping for a concise sensible solution.
I have a bound form purely for data entry (cannot browse records, only insert them).
I will have a lot of users that screw up. To avoid dirty data, I want them to confirm that the form is correct before submitting the record.
Problem is, as soon as I input ANYTHING on the form, access creates and saves a record.
I want the record to ONLY be saved and committed if the user clicks 'Submit'. If they click close or exit the application, I do not want that partially completed record in the database.
Without using an unbound form and calling an insert function, is there a simple solution?
An autonumber is there to be unique, not sequential. If you need a sequential number, do not use autonumber. Autonumber should never be shown to the user. It can never be relied upon to be anything but unique, and if you mess about enough, not even that.
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me.AText = "Invalid" Then
Me.Undo
Cancel = True
End If
End Sub
Note that a form with a subform may not work with undo, because the record is committed on change from the subform to the main form and vice versa and it all gets quite complicated.
Remou's method is definitely the quickest, here is another based on my comment ;)
Option Explicit
Private blnGood As Boolean
Private Sub cmdSubmit_Click()
blnGood = True
Call DoCmd.RunCommand(acCmdSaveRecord)
blnGood = False
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Not blnGood Then
Cancel = True
Call MsgBox(Prompt:="click submit to save the record", Title:="Before Update")
End If
End Sub
You can use the following code to create a clear button in case the user made an errors and wants to clear the entire form and start over.
Private Sub btnClear_Click()
If Me.Dirty = True Then
DoCmd.RunCommand acCmdUndo
Exit Sub
End If
End Sub`
I sometimes find the before_update event to act weird so I generally disable the close (x) button in properties and add a close button of my own that prompts the user if he wants to abandon the data on screen.
Private Sub close_Click()
Dim Answer As Integer
If Me.Dirty = True Then
Dim Response As Integer
' Displays a message box with the yes and no options.
Response = MsgBox(Prompt:="Do you wish to discard data?", Buttons:=vbYesNo)
' If statement to check if the yes button was selected.
If Response = vbYes Then
DoCmd.RunCommand acCmdUndo
DoCmd.Close
Else
Me.Clear.SetFocus
End If
Else
' The no button was selected.
DoCmd.Close
End If
End Sub