Error Checking Option Boxes - vba

I'm trying to build in an error checking for two option boxes I have:
projectOptionbox
implementOptionbox
This is the current code I have right now for error checking a couple of other things, just unsure as to what kind of code is necessary for option boxes:
Function CheckInputs() As Boolean
If Not CheckControl(Me.nameTextbox, "Please enter your Name") Then Exit Function
If Not CheckControl(Me.projectTextbox, "Please enter a Project Name") Then Exit Function
If Not CheckControl(Me.initiativeCombobox, "Please select an Initiative") Then Exit Function
If Not CheckControl(Me.audienceCombobox, "Please select an Audience") Then Exit Function
If Not CheckControl(Me.impactCombobox, "Please select an Impact Type") Then Exit Function
If Not CheckControl(Me.hoursTextbox, "Please enter the amount of Monthly Hours") Then Exit Function
If Not CheckControl(Me.peopleTextbox, "Please enter the amount of People on the Project") Then Exit Function
If Not CheckControl(Me.lengthListbox, "") Then If Not CheckControl(Me.lengthListbox2, "Please select Project Length") Then Exit Function
CheckInputs = True
End Function
Private Function CountSelectedListBoxItems(lb As MSForms.ListBox) As Long
Dim i As Long
With lb
For i = 0 To .ListCount - 1
If .Selected(i) Then CountSelectedListBoxItems = CountSelectedListBoxItems + 1
Next i
End With
End Function
Function CheckControl(ctrl As MSForms.Control, errMsg As String) As Boolean
Select Case TypeName(ctrl)
Case "TextBox"
CheckControl = Trim(ctrl.Value) <> ""
Case "ComboBox"
CheckControl = ctrl.ListIndex <> -1
Case "ListBox"
CheckControl = CountSelectedListBoxItems(ctrl) > 0
' Case Else
End Select
If errMsg = "" Then Exit Function
If CheckControl Then Exit Function
ctrl.SetFocus
MsgBox errMsg
End Function

From what I gathered from the post, it sounds like you want to develop a method of confirming that an OptionButton within a group has been selected. (Not looking for an application error per se, but rather a violation of your business logic).
This is a bit more complicated than the checks on the other controls because the other controls are standalone. There are two options. (1) Since the OptionButton control doesn't actually support a null state, you can set a default option on the Form's Initialization. Then, irrespective of what the user does, one of the options will always be selected.
The other option is to use the GroupName property of the OptionButtons to put buttons into a group. (When optionbuttons are in a group, this ensures that one of them is selected). Next, you can loop through all of the controls looking for OptionButtons of the same GroupName, then check if at least one of them is selected. A helper function such as the one below should do the trick:
Private Function OptionBoxGroupHasASelection(inputControl As MSForms.Control) As Boolean
Dim ctrl As MSForms.Control
Dim sGroup As String
Dim bOutput As Boolean
If TypeName(inputControl) <> "OptionButton" Then
OptionBoxGroupHasASelection = False
Exit Function
End If
If inputControl.Value = True Then
OptionBoxGroupHasASelection = True
Exit Function
End If
sGroup = inputControl.GroupName
bOutput = False
For Each ctrl In Me.Controls
If TypeName(ctrl) = "OptionButton" Then
If ctrl.GroupName = sGroup Then
If ctrl.Value = True Then
bOutput = True
Exit For
End If
End If
End If
Next ctrl
OptionBoxGroupHasASelection = bOutput
End Function

Related

How to detect if all checkboxes are disabled?

I have an access table that stores information about the steps completed on a product. When entering information, I have a form pop up asking which product they want to enter data for. Each record in the table gets its own checkbox (dynamically created). If information has already been recorded for that product, for that step then the checkbox is disabled. When all checkboxes are disabled I have a message box pop up saying all products for that step have been completed.
The issue: Say for whatever reason (operator choice, production reason, etc), work is done on product 4 for an order but not complete on 1, 2, 3. The code that I have says that all products have info entered just because that is the last record checked.
Dim Args As Variant
Dim i As Integer
Dim ctl As Control
Dim bCheck As Boolean
bCheck = False
If Not IsNull(Me.OpenArgs) Then
Args = Split(Me.OpenArgs, ";")
Me.txtForm = Args(0)
Me.lblChoices.Caption = Args(1)
End If
For Each ctl In Forms(Me.Name).Controls
If ctl.ControlType = acCheckBox Then
ctl.Value = False
If ctl.Enabled = True Then
bCheck = False
Else
bCheck = True
End If
End If
Next
If bCheck = True Then
fncMsgBox "Labor has been entered for all bundles on this step."
DoCmd.Close acForm, Me.Name
End If
This IF statement is the problem and its obvious to me why it doesn't work. I'm curious as to how I can get around this?
If ctl.Enabled = True Then
bCheck = False
Else
bCheck = True
End If
Exit the loop as soon as you find an enabled checkbox:
Dim Args As Variant
Dim i As Integer
Dim ctl As Control
Dim bCheck As Boolean
bCheck = False
If Not IsNull(Me.OpenArgs) Then
Args = Split(Me.OpenArgs, ";")
Me.txtForm = Args(0)
Me.lblChoices.Caption = Args(1)
End If
For Each ctl In Forms(Me.Name).Controls
If ctl.ControlType = acCheckBox Then
ctl.Value = False
If ctl.Enabled Then
bCheck = True
Exit For 'stop checking
End If
End If
Next
If bCheck Then
fncMsgBox "Labor has been entered for all bundles on this step."
DoCmd.Close acForm, Me.Name
End If
Note: you don't need = True in your If when the value you're checking already represents a boolean.

(Excel Userform) Check if all checkboxes in a Userform are checked

Never tried UserForm checkboxes before so I don't even know how to point to the Checkboxes in a Userform.
This is what I have at the moment....and I know, I know, it is completely wrong. Please help?
Private Sub Step1_Confirm_Click()
Dim i As Byte
Dim Done As Boolean
For i = 1 To 4
If Step1_(i).value = True Then
Done = True
End If
Next i
If Not Done = True Then
MsgBox "Please make sure you have done all"
End If
End Sub
Basically I have:
A Userform called IOSP_Acc_R_Approval_Step1
4 checkboxes called Step1_1; Step1_2; Step1_3; Step1_4
A button called Step1_Confirm
I want the button to show Error, if not all checkboxes are checked - meaning that all checkboxes have to be checked....(in case my English is too bad to convey my meaning)
Try the code below (explanations inside the code as comments):
Private Sub Step1_Confirm_Click()
Dim i As Long
Dim Ctrl As Control
' loop through all user_form control
For Each Ctrl In IOSP_Acc_R_Approval.Controls
If TypeName(Ctrl) = "CheckBox" Then ' check if control type is Check-Box
If Ctrl.Value = True Then ' check if check-box is checked
i = i + 1
End If
End If
Next Ctrl
If i < 4 Then ' not all 4 check-boxes are checked
MsgBox "Please make sure you have done all"
End If
End Sub
You can do this by:
assume that all checkboxes are checked by setting a flag to True
iterate the checkboxes and if one is not checked set the flag to False and exit
at the end of the loop, if all checkboxes were checked then the flag is still True
You can refer to the checkboxes dynamically by using the Me.Controls collection and pass in the name of the checkbox like "Step1_" & i.
Example code:
Option Explicit
Private Sub Step1_Confirm_Click()
Dim i As Long '<-- use Long, not Byte
Dim blnResult As Boolean
' set a flag to assume that it is true that all checkboxes are checked
blnResult = True
' get the value of each check box
For i = 1 To 4
If Me.Controls("Step1_" & i).Value = False Then
blnResult = False
Exit For '<-- skip loop if at least one box not checked
End If
Next i
' check the value of the flag
If blnResult = False Then
MsgBox "Please make sure you have done all"
Else
' all boxes checked ...
MsgBox "All checked"
End If
End Sub
Done=true
For i = 1 To 4
Done = Done*Step1_(i).value
Next i
if done `then`
msgbox "All checkboxes are checked"
end if

How to clear userform textbox without calling the _Change function?

I have a userform in Excel with textboxes meant for numeric data only. I want to clear the textbox when it detects bad entry and gives an error message, but I don't want to have the textbox's _Change function called again or else the message pops up twice because I change the text to "". I didn't see a built in clear function.. is there a better way to do this?
Private Sub txtbox1_Change()
txt = userform.txtbox1.Value
If Not IsNumeric(txt) Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
txtbox1.Text = ""
End If
End Sub
A simple way to achieve this is to use the _Exit() Function:
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If Not IsNumeric(TextBox1.Value) Then
MsgBox "Please only enter numeric values.", vbCritical, "Error"
End If
End Sub
This triggers as soon as the text box looses Focus.
prevent user from typing Alpha chars:
Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Select Case KeyAscii
Case Asc("0") To Asc("9")
Case Asc("-")
If Instr(1,Me.TextBox1.Text,"-") > 0 Or Me.TextBox1.SelStart > 0 Then
KeyAscii = 0
End If
Case Asc(".")
If InStr(1, Me.TextBox1.Text, ".") > 0 Then
KeyAscii = 0
End If
Case Else
KeyAscii = 0
End Select
End Sub
Hope this helps!
-Hugues
You can do this way, as shown here
Private Sub TextBox1_Change()
OnlyNumbers
End Sub
Private Sub OnlyNumbers()
If TypeName(Me.ActiveControl) = "TextBox" Then
With Me.ActiveControl
If Not IsNumeric(.Value) And .Value <> vbNullString Then
MsgBox "Sorry, only numbers allowed"
.Value = vbNullString
End If
End With
End If
End Sub
You can add this line at the very beginning
sub txtbox1_Change()
If txtbox1.Text = "" Or txtbox1.Text = "-" Then Exit Sub '<~~~
Alternatively, I found this even shorter and interesting:
Private Sub txtbox1_Change()
If Not IsNumeric(txtbox1.Text & "0") Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
txtbox1.Text = ""
End If
End Sub
The interesting part is that it accepts to enter things like ".2", "-3.2", and also "5e3", the last case being not allowed by the other methods!
Turning it into a while loop can remove only the last bad typed character(s):
Private Sub txtbox1_Change()
t = txtbox1.Text
Do While t <> "" And Not IsNumeric(t) And Not IsNumeric(t & "0")
t = Mid(t, 1, Len(t) - 1)
Loop
txtbox1.Text = t
End Sub
Seems since there is nothing built in that can do what I want, this would be the simplest way to handle the problem:
Private Sub txtbox1_Change()
txt = userform.txtbox1.Value
If (Not IsNumeric(txt)) And (txt <> "") Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
txtbox1.Text = ""
End If
End Sub
Declare a global boolean and at the beginning of each sub, add an if statement which exits the sub if the boolean is true. When you get an error message, set the value to true, and nothing will happen. Then set it to false again.
Dim ufEventsDisabled As Boolean
Private Sub txtbox1_Change()
'repeat the following line everywhere that you don't want to update
if ufeventsdisabled then exit sub
txt = userform.txtbox1.Value
If Not IsNumeric(txt) Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
ufeventsdisabled = true
txtbox1.Text = ""
ufeventsdisabled = false
End If
End Sub
*Credit goes to mikerickson from mrexcel.com
You can't stop the _Changed event from firing. I would advise you to back up a couple of steps in your design and ask if you can get the job done without having to clear it in the first place. In FoxPro we would set the 'format' to 9999.99 and it would automatically prevent users from typing alpha characters, but I think that particular field was unique to FP. You can hook the _Changed event and perform your own validation there. I would suggest not filtering individual key strokes, but validating the whole value each time it's changed.
If Text1.Value <> str(val(Text1.Value)) Then
Text1.Value = previousValue
EndIf
... which will require keeping a backup variable for the previous value, but I'm sure you can figure that out. There may be certain edge cases where VB's string-number conversion functions don't exactly match, like exponential notation as you mentioned, so you may need a more sophisticated check than that. Anyway, this will make it impossible to even enter a bad value. It also provides a better user experience because the feedback is more immediate and intuitive. You may notice that the value is being changed inside the _Changed event, which should raise a knee jerk red flag in your mind about infinite loops. If you do this, make sure that your previous value has already been validated, keeping in mind that the initial value will be an empty string. As such, the recursive call will skip over the If block thus terminating the loop. In any case, what you would consider "better" may differ depending on who you ask, but hopefully I've given you some food for thought.

MS Access, DoEvents to exit loop

What I'd like to accomplish:
Do While ctr < List and Break = False
code that works here...
DoEvents
If KeyDown = vbKeyQ
Break = True
End If
loop
Break out of a loop by holding down a key (eg, Q). I've read up on DoEvents during the loop in order to achieve the functionality that I want. The idea is to have a Do While loop run until either the end of the list is reached or when Q is held down. I'm having issues getting the code to work the way I want, so I'm reaching out to hopefully end the frustration. My experience with VBA is very limited.
UPDATE - More code to expose where the problem might be. This is all in the order I have it (in case order of subs makes a difference:
Private Sub Form_KeyPress(KeyAscii As Integer)
Dim strChar As String
strChar = UCase(Chr(KeyAscii))
If strChar = "Q" Then
blnQuit = True
Debug.Print "Q pressed"
End If
End Sub
Private Sub Master_Report_Click()
Dim i As Integer
Dim Deptarray
blnQuit= False
If IsNull(Me.Hospital) Then
MsgBox ("Please Choose a Hospital")
Else
DoCmd.OpenForm "Report Print/Update", acNormal, , , , acDialog
If Report_choice = "Current_List" Then
Debug.Print "Create master rec report"
DoCmd.OpenReport "Master Rec Report", acViewPreview
DoCmd.RunCommand acCmdZoom100
ElseIf Report_choice = "Update_All" Then
total = (DCM_Dept.ListCount - 1)
ctr = 1
Do While ctr < (DCM_Dept.ListCount) And LoopBreak = False
Debug.Print "LoopBreak: "; LoopBreak
Debug.Print "Counter: "; ctr
DCM_Dept.Value = DCM_Dept.Column(0, ctr)
Update_Site (Me.Hospital)
ctr = ctr + 1
'DoEvents
' If vbKeyQ = True Then
'LoopBreak = True
'End If
Loop
Debug.Print "Update loop exited"
Debug.Print "Create master rec report"
DoCmd.OpenReport "Master Rec Report", acViewPreview
DoCmd.RunCommand acCmdZoom100
Else
End If
End If
End Sub
Private Sub Update_Site(Site As String)
If IsNull(Me.Hospital) Then
MsgBox ("Please Choose a Hospital")
ElseIf IsNull(Me.DCM_Dept) Then
MsgBox ("Please Choose a Department")
ElseIf Site = "FORES" Then
Debug.Print "Run FORES update macro"
DoCmd.RunMacro "0 FORES Master Add/Update"
ElseIf Site = "SSIUH" Then
Debug.Print "Run SSIUH update macro"
DoCmd.RunMacro "0 SSIUH Master Add/Update"
End If
End Sub
Report_choice and LoopBreak are both Public variables. My original idea was to have a popup form floating over the main form to display a counter ("Processing department X of Y") and a button to break the loop on there. I realized that the form was unresponsive while the Update_Site() was running its macro so I decided to go with holding a key down instead.
So, where do I go from here to get OnKeyDown to work? Or, is there a better way to do it?
Try to set the Key Preview of the form to Yes and add a variable blnQuit and a key press event in your form like this:
Private blnQuit As Boolean
'form
Private Sub Form_KeyPress(KeyAscii As Integer)
Dim strChar As String
strChar = UCase(Chr(KeyAscii))
If strChar = "Q" Then
blnQuit = True
End If
End Sub
Then check the blnQuit in your Do While condition, like this:
blnQuit = False
Do While ctr < List And Not blnQuit
code that works here...
DoEvents
loop

How can I check whether the data already exists in combobox list?

How can I check if the data from cmbTypeYacht.text already exists in cmbTypeYacht.list?
Here's what I've got:
Dim TypeYacht As String 'Type of yacht input
TypeYacht = cmbTypeYacht.Text
If TypeYacht = ("cmbTypeYacht list") Then
MsgBox "Type of Yacht is already on the list", vbExclamation, "Yacht Chantering"
Else
cmbTypeYacht.AddItem cmbTypeYacht.Text
With cmbTypeYacht
.Text = ""
.SetFocus
End With
End If
sorry about the tag im not quite sure which is it but im using Microsoft Visual Basic app.
The ComboBox class has a FindStringExact() method that will do the trick for you, like this:
Dim resultIndex As Integer = -1
resultIndex = cmbTypeYacht.FindStringExact(cmbTypeYacht.Text)
If resultIndex > -1 Then
' Found text, do something here
MessageBox.Show("Found It")
Else
' Did not find text, do something here
MessageBox.Show("Did Not Find It")
End If
You can also just loop through the list as well, like this:
Dim i As Integer = 0
For i = 0 To cmbTypeYacht.Items.Count - 1
If cmbTypeYacht.Items.Contains(cmbTypeYacht.Text) Then
MessageBox.Show("Found It")
Exit For
End If
Next
I'm working in Excel 2013 and there is no FindStringExact or .Items.Contains so, neither of those are valid. There is also no need to iterate the list. It is very simple actually. Given a userform "MyUserForm" and a combobox "MyComboBox",
If MyUserForm.MyComboBox.ListIndex >= 0 Then
MsgBox "Item is in the list"
Else
MsgBox "Item is NOT in the list"
End If
Explanation: If selected item is not in the list, .ListIndex returns -1.
The combobox in vba has a property called MatchFound. It will return true if the value you inputted in the combobox (ComboBox.Value) existed before.
Put below code in the update event of the combobox for trial
Private Sub ComboBox_AfterUpdate()
If ComboBox.MatchFound = True then
Msgbox "Value exist"
End If
End Sub
Check it out:
https://msdn.microsoft.com/en-us/vba/outlook-vba/articles/combobox-matchfound-property-outlook-forms-script
You do not need to iterate through combobox.items. Items.Contains will already iterate through the list for you.
Simply use:
If cmbTypeYacht.Items.Contains(cmbTypeYacht.Text) Then
MessageBox.Show("Found It")
Exit For
End If
Searching: VBA check whether the data already exists in combobox list?
but vba doesnt have the properties above.
Sub TestString()
Dim myString As String
Dim i As Long
Dim strFound As Boolean
'Just for test purposes
myString = "Apple"
strFound = False
With Me.ComboBox1
'Loop through combobox
For i = 0 To .ListCount - 1
If .List(i) = myString Then
strFound = True
Exit For
End If
Next i
'Check if we should add item
If Not strFound Then .AddItem (myString)
End With
End Sub
This was found after a lot of searching at http://www.ozgrid.com/forum/showthread.php?t=187763
and actually works