MS Access Form VBA Check Checkboxes, Before Checking Others? - vba

I am working on an Access application, with a SQL back-end.
I have a form for people, where each person can need to have different things checked or unchecked. There are the following fields and corresponding controls on the form:
No Options (integer - boolean - checkbox)
Option A (integer - boolean - checkbox)
Option A Amount (money)
Option B (integer - boolean - checkbox)
Option B Amount (money)
Option C (integer - boolean - checkbox)
Option C Amount (money)
Option D (integer - boolean - checkbox)
Option D command button (opens popup form with option type drop down and amounts for multiple values to be entered).
My concern is that if someone checks one box, it can conflict with another checkbox or money fields.
If someone checks No Options, and one of the other options is checked, I have to uncheck those. I also need to 0 out their corresponding money field. If there are Option D "Other Option" records, in a linked table, then I need to delete those too, after I confirm with the user. I also want to disable the checkboxes and money/ command button controls for options A - D.
If I am unchecking No Options, then I need to enable all of that.
You can start to see how every time I check any of the No Options, or Options A - D, I have to check the state of No Options, and the option's corresponding money amount, to confirm the user wants to make this change.
To do that, I set up the following code for the No Options Before update:
Private Sub NoOptions_BeforeUpdate(Cancel As Integer)
Dim Msg, Style, Title
Dim delOLiensSQL
If Me.NoOptions = False Then
If (Me.OptionA = True Or Me.OptionB = True Or Me.OptionC = True Or Me.OptionD = True) Then
Msg = "You have chosen No Options, but one or more option is checked." & vbCrLf & _
"Choosing No Options will require removing all Lien amounts." & vbCrLf & _
"Would you like to change this Person to No Options?"
Style = vbYesNo
Title = "All Options Will Be Reset to 0 and False."
Response = MsgBox(Msg, Style, Title)
If Response = vbYes Then
If Nz(DLookup("ID", "tblPersonOtherOptionsD", "FKPerson = " & Me.ID), 0) Then
delOLiensSQL = "Delete From tblPersonOtherOptionsD Where FKPerson = " & Me.ID
DoCmd.RunSQL delOoptionssSQL, dbSeeChanges
End If
Me.OptionA = False
Me.OptionAAmount = 0
Me.OptionB = False
Me.OptionBAmount = 0
Me.OptionC = False
Me.OptionCAmount = 0
Me.OptionD = False
OptionsAllowPubFunc (False)
Else
Me.Undo
MsgBox "OK, we will leave everything as it is.", vbOKOnly, "Better Safe Than Sorry"
End If
Else
Me.NoOptions = True
End If
Else
Me.NoOptions = False
End If
End Sub
OptionsAllowPubFunc (False) is a public function which is the following:
Public Function PlaintiffLiensAllowed(Liens As Boolean)
Forms!frmPerson.OptionAAmount.Enabled = Liens
Forms!frmPerson.OptionBAmount.Enabled = Liens
Forms!frmPerson.OptionCAmount.Enabled = Liens
Forms!frmPerson.OptionDAmount.Enabled = Liens
End Function
I also set up Before Update public function for OptionA, OptionB, OptionC, OptionD as follows:
Public Function ChangeAOption(OptionCheck As Control, OptionAmount As Control, OptionName As String)
Dim Msg, Style, Title
Dim Msg2, Style2, Title2
If OptionCheck = True Then
If Nz(OptionAmount, 0) > 0 Then
Msg = "There is a " & OptionName & " Option amount. Unchecking " & OptionName & " Option, will require the amount to be 0." & vbCrLf & _
"Would you like to uncheck " & OptionName & " Option and make the amount 0?"
Style = vbYesNo
Title = "Confirm No " & OptionName & " Option."
Response = MsgBox(Msg, Style, Title)
If Response = vbYes Then
OptionAmount = 0
OptionCheck = False
Else
OptionCheck.Undo
MsgBox "Ok, we will leave it as is.", vbOKOnly, "Better Safe Than Sorry."
End If
Else
OptionCheck = False
End If
Else
If Forms!frmPerson.NoOptions = True Then
Msg2 = "No Options is Checked. Checking " & OptionName & " Options will require no Options to be unchecked." & vbCrLf & _
"Would you like to uncheck no Options?"
Style2 = vbYesNo
Title2 = "Confirm No Options False."
Response2 = MsgBox(Msg2, Style2, Title2)
If Response2 = vbYes Then
OptionsAllowPubFunc (True)
Forms!frmPerson.NoOptions = False
OptionCheck = True
Else
OptionCheck = True
End If
Else
OptionCheck = True
End If
End Function
I'm testing this, and when I try to check the No Options checkbox, changing it from false to true, I get a run-time error '-2147352567 (80020009)':
The macro or function set to BeforeUpdate or ValidationRule property
for this field is preventing the [People application] from saving data
in the field.
Anyone know what I'm doing wrong? Is there a more simple way to do this?
Thank you!!!

From my recent experience, when the Before Update event is triggered it uses the new value of the field in any calculations. So I'd expect you to want to start that main If statement like If Me.NoOptions = True Then.
I also don't believe you need the Else OptionCheck = True bits just before the End Ifs.
What may be causing a problem is you've called OptionsAllowPubFunc, but the function you've included in this question is actually called PlaintiffLiensAllowed - unless you have an identical function called OptionsAllowPubFunc, this'll give you an error.
Finally, I've never found me.undo to be especially helpful in this kind of context, but the Before Update gives you an out - just tell it to cancel using Cancel = True (or anything that isn't 0) and it'll not update the field and exit the sub.
You could also add in a bit to re-enable the option fields if they were un-checking the box.
Try running it as:
Private Sub NoOptions_BeforeUpdate(Cancel As Integer)
Dim Msg As String, Style As VbMsgBoxStyle, Title As String
Dim Response As VbMsgBoxResult, delOLiensSQL As String
If Me.NoOptions = True Then
If (Me.OptionA = True Or Me.OptionB = True Or Me.OptionC = True Or Me.OptionD = True) Then
Msg = "You have chosen No Options, but one or more option is checked." & vbCrLf & _
"Choosing No Options will require removing all Lien amounts." & vbCrLf & _
"Would you like to change this Person to No Options?"
Style = vbYesNo
Title = "All Options Will Be Reset to 0 and False."
Response = MsgBox(Msg, Style, Title)
If Response = vbYes Then
If Nz(DLookup("ID", "tblPersonOtherOptionsD", "FKPerson = " & Me.ID), 0) Then
delOLiensSQL = "Delete From tblPersonOtherOptionsD Where FKPerson = " & Me.ID
DoCmd.RunSQL delOoptionssSQL, dbSeeChanges
End If
Me.OptionA = False
Me.OptionAAmount = 0
Me.OptionB = False
Me.OptionBAmount = 0
Me.OptionC = False
Me.OptionCAmount = 0
Me.OptionD = False
PlaintiffLiensAllowed(False)
Else
MsgBox "OK, we will leave everything as it is.", vbOKOnly, "Better Safe Than Sorry"
Cancel = True
End If
End If
Else
PlaintiffLiensAllowed(True)
End If
End Sub

Related

listbox vba : listcount doesn't update immediately

Hello everyone and thanks in advance for the help.
Shortly: I have a textbox used to input a name to search. According to this "name", A listbox update with all the record found from a table (and following, cliking on the listbox I update a form).
Question: I want some actions (for example a msgbox...) when there are not records founds (I think that listbox.listcount is 1 in this case but often from the immediate windows is 0???).
"Menu" is the form that cointains Listbox and textbox, "globale" is a table and "nominativo" a field of globale.
So the code pass away (lbox.listcount doesn't update) and only if I set a break point it runs...
Mistery!!
My code ( I learned some development by myself).
Private Sub Comando156_Click() 'to make blank all the boxes
Me.RecordSource = ""
Me.Refresh
Testo129.Value = ""
Testo154.Value = ""
nomin_lbox.RowSource = ""
End Sub
Private Sub nomin_lbox_AfterUpdate()
chiave1 = nomin_lbox.Column(6)
sql1 = "SELECT * FROM globale WHERE (globale.id) =" & chiave1
Forms!menu.RecordSource = sql1
Forms!menu.Refresh
nomin_lbox.Requery
End Sub
Private Sub Testo129_AfterUpdate()
If Testo129 <> "" Then
chiave2 = Testo129
sql1 = "SELECT * FROM globale WHERE [nominativo] like'*" & chiave2 & "*'" & ""
nomin_lbox.RowSource = sql1
nomin_lbox.Requery
n_found = nomin_lbox.ListCount
If n_found = 1 Then
MsgBox "niente"
End If
Forms!menu.Refresh
Else
Me.RecordSource = "SELECT * FROM globale"
Me.Refresh
End If
End Sub`

Conditional formatting prevents combobox dropdown on continuous form

The following code filters the dropdown list of a combobox in a continuous subform and allows the user to move up and down the dropdown to select data
'Move through the dropdown using up/down arrow keys
Private Sub IngCombo_KeyDown(KeyCode As Integer, Shift As Integer)
Dim MsgBoxResponse As String
Select Case KeyCode
'Tab button is pressed with "" in the field. Access returns a warning message if not dealt with
Case 9 'Tab Button
If Me.IngCombo.Text = "" Then
MsgBoxResponse = MsgBox("Ingredient you entered is not in the list" & vbCrLf & "Would you like to try again?", vbYesNo, "Ingredient not recognised")
Select Case MsgBoxResponse
Case Is = 6
KeyCode = 0
Case Is = 7
KeyCode = 0
Me.Undo
End Select
End If
Case vbKeyDown
Me.IngCombo.Selected(Me.IngCombo.ListIndex + 1) = True
KeyCode = 0
Me.IngCombo.DropDown
Case vbKeyUp
Me.IngCombo.Selected(Me.IngCombo.ListIndex - 1) = True
KeyCode = 0
Me.IngCombo.DropDown
Case vbKeyEscape
Me.IngCombo.Text = ""
Me.Undo
End Select
End Sub
Private Sub IngCombo_KeyUp(KeyCode As Integer, Shift As Integer)
'Filter dropdown to match what the user has typed
'This combo's control source is the IngredientID, but the ID is hidden, hence the SQL selects both the ID and Ingredient text
Dim UserText As String
If Len(Me.IngCombo.Text) > 0 Then
UserText = Me.IngCombo.Text
Me.IngCombo.RowSource = "SELECT IngredientsTbl.IngredientID, IngredientsTbl.Ingredient " _
& "FROM IngredientsTbl WHERE (((IngredientsTbl.Ingredient) LIKE '*" & UserText & "*'));"
If Me.IngCombo.ListCount > 0 Then
Me.IngCombo.DropDown
End If
Else
Me.IngCombo.RowSource = "SELECT IngredientsTbl.IngredientID, IngredientsTbl.Ingredient " _
& "FROM IngredientsTbl;"
End If
End Sub
Private Sub IngCombo_LostFocus()
Me.IngCombo.RowSource = "SELECT IngredientsTbl.IngredientID, IngredientsTbl.Ingredient " _
& "FROM IngredientsTbl ORDER BY IngredientsTbl.Ingredient;"
End Sub
'If user types string that is found by the 'Key Up' routine above but is in the middle of a string i.e. 'milk' is typed and 'buttermilk' is highlighted
'Then pressing tab results in the not in list error
Private Sub IngCombo_NotInList(NewData As String, Response As Integer)
MsgBox "No ingredient matches your search", vbOKOnly, "Nothing Found"
Me.IngCombo = ""
Response = acDataErrContinue
End Sub
This works as intended.
I then add a conditional format, [text19]>50, to the ‘IngCombo’ combobox. This also works as intended but changes the behaviour of the 'IngCombo' combobox. The dropdown no longer appears, and when the user types in the ‘IngCombo’ field of a new record, it has the effect of filtering the text in the ‘IngCombo’ field of the other records of the continuous form. Eg if the user types ‘mint’, then records that contain mint in ‘IngCombo’ are shown, but all the others are blank.
The word ‘calculating’ appears momentarily in the bottom left, replacing the words 'form view' after a key is pressed. I assume this is the conditional formatting doing its work and disrupting the code, as ‘calculating’ does not appear when there is no conditional formatting.
Is there a way of maintaining the functionailty of the code and also having the conditional formating
Update after June7's comment that referenced Allen Browne code.Tried moving code into a Private Sub that is called from the combo's Change event
Private Sub IngCombo_Change()
Dim Cmbo As ComboBox
Set Cmbo = Me.IngCombo
Dim NewText As String
NewText = Cmbo.Text
Call ReloadIngCombo(NewText)
End Sub
Private Sub ReloadIngCombo(UserText As String)
If Len(UserText) > 1 Then
Me.IngCombo.RowSource = "SELECT IngredientsTbl.IngredientID, IngredientsTbl.Ingredient " _
& "FROM IngredientsTbl WHERE (((IngredientsTbl.Ingredient) LIKE '*" & UserText & "*'));"
If Me.IngCombo.ListCount > 0 Then
Me.IngCombo.DropDown
End If
Else
Me.IngCombo.RowSource = "SELECT IngredientsTbl.IngredientID, IngredientsTbl.Ingredient " _
& "FROM IngredientsTbl;"
End If
End Sub
This works as intended. Adding a conditional format to the combobox prevents the dropdowns being shown to the user

Adding Multiple TreeNode Levels with Multi threading

i'm having alot of trouble trying to get a background worker properly functioning to populate a couple of TreeView Nodes. In said TreeView i have multiple levels of Nodes. For example
FileName
Model
Test & Result.
Model refers to a MicroStation Model (CAD Drawing Program), easiest way to explain it is a Sheet within a Spreadsheet.
I'm using a FileDialog to select files, once the files are selected each filename is added to the TreeView with its own Node.
The idea is that the program will then open each file, scan each model and add a sub TreeNode under the files Node wih the type of test and the result.
The DoWork function for the Background worker is below. I have removed alot of the code to simply my post. But there are 7 "tests" that the program does, i have included 2.
In the below example, "CheckFonts" is a function that just counts the text elements in a file and returns a number.
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i As Integer = 0 To m_CountTo
If BackgroundWorker1.CancellationPending Then
e.Cancel = True ' Set Cancel to True
Exit For
End If
Dim sError As String = ""
Dim bBorderFound As Boolean = False
Dim oDesignFile As DesignFile
Dim oModel As ModelReference
Dim oFontNode As New TreeNode
Dim oFontResultNode As New TreeNode
For Each oNode As TreeNode In trvItems.Nodes
Dim ustn As New MicroStationDGN.Application
oDesignFile = ustn.OpenDesignFileForProgram(oNode.Text, True)
For Each oModel In oDesignFile.Models
'####### Checks for Items on Default Level #######
If bDefaultPass = True Then
Dim iDefaultItems As Long
iDefaultItems = DefaultItems(oModel)
If iDefaultItems > 0 Then
sDefaultMessage = "There are " & iDefaultItems & " items on the Default Level"
bDefaultPass = False
Else
sDefaultMessage = "There are no items on the Default Level"
bDefaultPass = True
End If
End If
'####### Checks for Non Standard Fonts #######
If bFontPass = True Then
Dim iFontCheck As Long
iFontCheck = CheckFonts(oModel)
If iFontCheck > 0 Then
sFontMessage = "There are " & iFontCheck & " Text Elements that use a Non Standard Font."
bFontPass = False
ElseIf iFontCheck = -99999 Then
sFontMessage = "There are some corrupt or invalid Fonts used in the Design File"
bFontPass = False
Else
sFontMessage = "All Text Elements use the Correct Font"
bFontPass = True
End If
End If
Next ' End Model
oFontNode = oNode.Nodes.Add("Font Check")
oFontResultNode = oFontNode.Nodes.Add("")
If bFontPass = True Then
oFontResultNode.Text = "PASS - " & sFontMessage
oFontResultNode.ImageIndex = 0
oNode.Collapse()
Else
oFontResultNode.Text = "FAIL - " & sFontMessage
bPass = False
oFontResultNode.ImageIndex = 1
oFontNode.ImageIndex = 1
oNode.Expand()
oFontNode.Expand()
End If
oDefaultItemsNode = oNode.Nodes.Add("Default Items Check")
oDefaultItemsResultNode = oDefaultItemsNode.Nodes.Add("")
If bDefaultPass = True Then
oDefaultItemsResultNode.Text = "PASS - " & sDefaultMessage
oDefaultItemsResultNode.ImageIndex = 0
oNode.Collapse()
Else
oDefaultItemsResultNode.Text = "FAIL - " & sDefaultMessage
oDefaultItemsResultNode.ImageIndex = 1
oDefaultItemsResultNode.ImageIndex = 1
oNode.Expand()
bPass = False
End If
Next ' End File
Next
End Sub
I have worked with Background Workers before but this is a bit more complex to what i have done, i understand that you cant update controls from a different thread and that Invoke is used to pass it information. But i'm confused how to do it with multiple nodes. The best example I saw was here
Adding nodes to treeview with Begin Invoke / Invoke
But with multiple nodes the code became quite confusing and didn't work. The error message keeps coming up regarding the Invoke / BeginInvoke being called.
So, i guess my main question is where i would call the Invoke command to best make use of the Background worker?
Thanks in advance!!

VBA EXCEL: Use value in Listbox as Lookup value in the Match WorksheetFunction

I would like to know how to lookup a value selected from a Listbox (clicked) using application.worksheetfunction.match(lookup_value, lookuparray, match type)
edit:
This is a "supposed" to be a button (Reservebutton) the "ReservationName" is a textbox the reserve button adds the number from the available listbox to the reserved listbox and then deletes the number selected in the available listbox. i'm a beginner in coding, so mind my mistakes please.
thanks a lot.
Private Sub ReserveButton_Click()
Dim Locator, RowData, NListBoxValue As Double
Locator = Application.WorksheetFunction.Count(Worksheets("Reserved").Range("A:A"))
For r = 0 To AvailableNumberList.ListCount - 1
RowData = Application.WorksheetFunction.Match(AvailableNumberList.List(r), Worksheets("Activation").Range("A:A"), 0)
If AvailableNumberList.Selected(r) = True Then
If ReservationName.Value = "" Or ReservationName.Value = "Enter Full Name" Then
ErrorResult = MsgBox("Error: Name field is empty", vbCritical + vbOKOnly, "Error In Field")
ElseIf Application.WorksheetFunction.VLookup(AvailableNumberList.List(r), Activation.Range("A:E"), 4, False) <> "FREE" Then
ErrorResult = MsgBox("Error: Number is Not Free", vbCritical + vbOKOnly, "Error In Reservation")
Else
ReservedNumberList.AddItem AvailableNumberList.List(r)
Worksheets("Reserved").Range("A" & Locator + 2) = AvailableNumberList.List(r)
Worksheets("Reserved").Range("B" & Locator + 2) = Worksheets("Activation").Cells(RowData, 2)
Worksheets("Reserved").Range("C" & Locator + 2) = Worksheets("Activation").Cells(RowData, 3)
Worksheets("Reserved").Range("D" & Locator + 2) = ReservationName.Value
AvailableNumberList.Clear
Worksheets("Reserved").Rows(RowData).Delete
ThisWorkbook.Save
Call AvailableList
End If
End If
Next r
End Sub
Code:
Application.WorksheetFunction.Match(<Form>.<Listbox>,Range("<LookupSheet>!A:A"),0)

VB.NET LISTBOX [in and out]

I was actually working an Attendance System, using listbox i want to monitor whether "employees" timed in or out.
txtEmpNum.text as my textbox,
rdTin as my radio button for time in,
rdTout as my radio button for time out,
lblName, lblDept, lblinout are just label. I want that if a user already timed in his/her name wont appear on my listbox rather msgbox pop up. But on this code although msgbox poped up, still the name of the employee appears on my listbox.
If txtEmpNum.Text = 8888 Then
If rdTin.Checked = True Then
For i As Integer = 0 To listEmp.Items.Count - 1
If (listEmp.Items(i).ToString.Contains("Bane Lim")) Then
MsgBox("String found at " & (i + 1).ToString)
Exit For
End If
Next
lblName.Text = "Bane"
lblDept.Text = "Admin"
lblinout.Text = "In"
listEmp.Items.Add("Bane Lim")
txtEmpNum.Clear()
ElseIf rdTout.Checked = True Then
lblName.Text = "Bane"
lblDept.Text = "Admin"
lblinout.Text = "Out"
listEmp.Items.Remove("Bane Lim")
txtEmpNum.Clear()
End If
Is the problem that the name is appearing a second time? You'll want to Exit Sub or Exit Function rather than Exit For. Exit For is kicking it from the loop but continuing with the remaining code (to add again).
Otherwise add a flag in there like:
If txtEmpNum.Text = 8888 Then
If rdTin.Checked = True Then
Dim bolFound As Boolean = False
For i As Integer = 0 To listEmp.Items.Count - 1
If (listEmp.Items(i).ToString.Contains("Bane Lim")) Then
MsgBox("String found at " & (i + 1).ToString)
bolFound = True
Exit For
End If
Next
If Not bolFound Then
lblName.Text = "Bane"
lblDept.Text = "Admin"
lblinout.Text = "In"
listEmp.Items.Add("Bane Lim")
txtEmpNum.Clear()
End If
ElseIf rdTout.Checked = True Then
lblName.Text = "Bane"
lblDept.Text = "Admin"
lblinout.Text = "Out"
listEmp.Items.Remove("Bane Lim")
txtEmpNum.Clear()
End If