I want to set up a public function like the following:
(A)
Public Function CheckYNField(chkControl As Control, chkField As String)
If chkField = "Y" Then
chkControl = -1
ElseIf chkField = "N" Then
chkControl = 0
Else: chkControl = 0
End If
End Function
(B)
Public Function CheckYNFlipper(chkControl As Control, chkField As String)
If chkField = "Y" Then
chkField = "N"
chkControl = 0
ElseIf chkField = "N" Then
chkField = "Y"
chkControl = -1
Else: chkField = "Y"
chkControl = -1
End If
End Function
The reason for this is, that I have a form, which has an underlying SQL table. I have no control over the data, but I must represent it, for the ability to maintain it. I have 10 fields, in the underlying table, which have a Y or N as their values. The data types are actually nvarchar(10). At the same time, I have to show these fields as checkbox controls, on the form, for ease of use.
The above code, is an attempt I am making to A - set the checkbox control to align with the current value in the table--> -1 = Y and 0 = N, and to B - update the table value, and switch the check box to checked or unchecked, from what it was, to the opposite, based on the onclick event of that control.
I want to make chkField and chkControl variables to the public function, that would be the table-field, and the form-control. I can't seem to get the right syntax, and was hoping someone might have clarification on how to do this.
for the form load and current, I tried this:
CheckYNField Forms("frmFormNameA").Controls(chkCheckNameA), tblTableName.FieldA
for the on click, I tried this:
CheckYNFlipper Forms("frmFormNameA").Controls(chkCheckNameA), tblTableName.FieldA
I've tried some other methods, but doesn't seem to be working. I'm doing something wrong, but I can't tell what. Appreciate any tips!
Edit/Update:
I tried Kostas K.'s solution, abandoning the idea of making a public functions with parameters for the fields and controls. I put the following, on load and on current:
With Me
If .txtfieldboundtablefieldA.Value = "Y" Then
.unboundchkA.Value = True
ElseIf .txtfieldboundtablefieldA.Value = "N" Then
.unboundchkA.Value = False
Else: .unboundchkA.Value = False
End If
End With
This is on a continuous form, so that it can show like a giant grid. There are the identifying bound field controls, and then a series of these checkboxes, to display the Y/N true/false status of each of these particular fields. I can't bound the checkboxes to the fields, because it changes the field value in the table to -1 or 0, and we need it to stay Y or N. I added a bound text field, to hold the table/field value for each row (hence the call to a text box control in the above revised code). The checkbox is unbound, and is there to display the field value, and allow the user to check and uncheck, so I can use on-click code to change the table field value between Y and N.
The above code is not seeming to show the correct checkbox value for each bound text field, based on each row. It shows based on the row that currently has focus. If I click on a row, where the table field is Y, all rows checkboxes on the form show true. If I move to a row, where the table field is N, all checkboxes for all rows change to false. I am struggling to just initially get 1 checkbox to show accurately, on every row of the continuous form, based on every record in the table. This is a small table, like 30 records. I really didn't think it would be so difficult to present this the way we need to.
Any ideas, how I could better do this?
Edit:
Set the Control Source of the checkbox to:
= IIf([YourYesNoField] = "Y", -1, 0)
In order to update when clicked:
Private Sub chkCheckNameA_Click()
Dim yesNo As String
yesNo = IIf(Me.chkCheckNameA.Value = 0, "Y", "N") 'reverse value
CurrentDb.Execute "Update [YourTable] SET [YourYesNoField]='" & yesNo & "' WHERE [ID]=" & Me![ID], dbFailOnError
Me.Requery
End Sub
You could try something this.
Check the Y/N field and assign the function's boolean return value to the checkbox (A).
On the checkbox click event, check its value and update the Y/N field (B).
'Form Load
Private Sub Form_Load()
With Me
.chkCheckNameA.Value = CheckYNField(![FieldA])
End With
End Sub
'Click
Private Sub chkCheckNameA_Click()
With Me
![FieldA] = IIf(.chkCheckNameA.Value = 0, "N", "Y")
End With
End Sub
'True returns -1, False returns 0
Private Function CheckYNField(ByVal chkField As String) As Boolean
CheckYNField = (chkField = "Y")
End Function
chkControl is a Control, so you need to access a property of that control. Try changing your code to:
Public Function CheckYNField(chkControl As Control, chkField As String)
If chkField = "Y" Then
chkControl.Value = -1
ElseIf chkField = "N" Then
chkControl.Value = 0
Else: chkControl.Value = 0
End If
End Function
and then the same idea in your other function.
Related
I'd like to disable text boxes if the SponName combo box contains certain company names. I thought I could try a for loop for this, but I'm not sure if I created the right variables or used the for loop properly. Please help!
I've tried cobbling together the following code from the threads below but can't quite adapt it to my problem. I'm still learning VBA and am not great with declaring variables. There's no error message, but the text fields just won't disable after updating SponName.
VBA code for if like multiple criteria
Private Sub SponName_AfterUpdate()
Dim sponcontains As Variant
sponcontains = SponName.Text
Criteria = Array("Company1*", "Company2*", "Company3*", "Company24*")
For i = LBound(Criteria) To UBound(Criteria)
If InStr(sponcontains, Criteria(i)) > 0 Then
cps_manufsite_name.Enabled = False
cps_manufsite_city.Enabled = False
cps_manufsite_st.Enabled = False
cps_manufsite_ctry.Enabled = False
Else
cps_manufsite_name.Enabled = True
cps_manufsite_city.Enabled = True
cps_manufsite_st.Enabled = True
cps_manufsite_ctry.Enabled = True
End If
Next i
End Sub
Use Text property only when control still has focus. You need Value property which is default for data controls so don't have to reference. Explicitly declare all variables. Should have Option Explicit at top of all modules. Set the VBA editor > Tools > Options > Require Variable Declaration to automatically add to new modules - will have to type into existing. Use of * wildcard not appropriate with InStr() function - it's just another literal character.
Like this - default value for Boolean variable is False:
Option Compare Database
Option Explicit
___________________________________________________________________________________
Private Sub SponName_AfterUpdate()
Dim sponcontains As Variant, criteria As Variant, booE As Boolean, i As Integer
sponcontains = Me.SponName
criteria = Array("Company1", "Company2", "Company3", "Company24")
For i = LBound(criteria) To UBound(criteria)
If InStr(sponcontains, criteria(i)) > 0 Then
booE = True
Exit For
End If
Next
cps_manufsite_name.Enabled = Not booE
cps_manufsite_city.Enabled = Not booE
cps_manufsite_st.Enabled = Not booE
cps_manufsite_ctry.Enabled = Not booE
End Sub
But your solution without loop is just as valid and most likely shorter. Again, use Boolean variable to set Enabled state instead of duplicating.
booE = InStr("Company1,Company2,Company3,Company24", Me.SponName) > 0
Consider what would happen if you had to modify this list. Would have to modify code and distribute new db version to users. Alternatively, use a table with an attribute (can be a yes/no field) for company status. Code can do a lookup to table. Better to use company ID value to search. Your combobox should have that as a column in its RowSource and usually that would be the combobox's value.
booE = DLookup("Status", "Companies", "CompanyID = " & Me.SponName)
Use of Conditional Formatting can often avoid VBA altogether.
i have a ms access formular where there are given several Information. For "Status" Combobox there are several options like "1","2","3","4". If "4" is selected in "cbx_Status" then I want to add in Textbox "txt_ID_Order" an automatically increased ID and give an Order Time in textbox "txt_OrderTime". That's why I wrote this and works well:
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me.cbx_Status.Value = "4" Then
Me.txt_OrderTime = Now()
Me.txt_ID_Order = DMax("[ID_Order]", "tblX") + 1
Else:
Me.txt_ID_Order=""
Me.txt_OrderTime = ""
End If
End Sub
However, if Status "4" is for some reason changed and again selected , I want to keep that old ID. But right know wenn i do that, it's still increasing ID.
How can I fix it?
Thanks
Check for a value:
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me!cbx_Status.Value = "4" Then
If IsNull(Me!txt_OrderTime.Value) Then
Me!txt_OrderTime.Value = Now()
Me!txt_ID_Order.Value = DMax("[ID_Order]", "tblX") + 1
End If
Else
Me!txt_ID_Order.Value = Null
Me!txt_OrderTime.Value = Null
End If
End Sub
Not sure about the logic though; if you select anything else than 4, the textboxes will be cleared.
I tried reading other posted questions about this error but I am still having trouble understanding it.
I was having errors after renaming variables and posted this question, I use option explicit and debug my code and it fixed my naming problems, But I still am having one problem in that 2 out of my 21 comboboxes in the operations row are still getting this same error. How can they get an error when they are using the same functions as the other 19. I checked their names and they are correct how could this be??
I have a form that I have build that is set up to look and function similar to and excel spreadsheet. This is the layout, Column Names first and then Control type
Operation Time/Min DecTime LaborRate Cost MarkUp Total
ComboBox TextBox Label Label Label TextBox Label
So all together I have 7 columns with 21 rows (not including column names) in which I can input data. Any where there is a label there is no user input its value is simply derived from the other fields.
I used the following naming convention for my form controls cb_op1, cb_op2, cb_op3 ... I just increment it by one to mimic the row number (control name plus row number). Operation = cb_op, Time = tb_time, DecTime = tb_Dectime, LaborRate = tb_LbrRate, Cost = tb_Cost, MarkUp = tb_MU, Total = tb_Total.
I wrote functions for the AfterUpdate events for my controls. This first function gets the value of the control based on its row number and then allows me to assign it to a variable this fuction is used for multiple controls update events.
Private Function GetControlValue(name As String) As Object
Dim obj As Object
For Each obj In Me.Controls
If obj.name = name Then
Set GetControlValue = obj
Exit Function
End If
Next
End Function
The next function is used to actually update the other field in the row based on the after update event. I use the GetControlValue Function listed above in this function. This is just for the operations column.
Private Function OperationsUpdate(RowNumber As Integer)
Dim Operations As Object
Dim Time As Object
Dim DecTime As Object
Dim LaborRate As Object
Set Operations = GetControlValue("cb_op" & RowNumber)
Set Time = GetControlValue("tb_time" & RowNumber)
Set DecTime = GetControlValue("tb_DecTime" & RowNumber)
Set LaborRate = GetControlValue("tb_LbrRate" & RowNumber)
Set Cost = GetControlValue("tb_Cost" & RowNumber)
If IsNull(Time.Value) Then
If IsNull(Operation.Value) Then
Cost.Value = ""
LaborRate.Value = ""
Else
LaborRate.Value = DLookup("LaborRate", "OperationsType", "[operationsID] = " & Operation.Value)
End If
Else
If IsNull(Operation.Value) Then
Cost.Value = ""
LaborRate.Value = ""
Else
LaborRate.Value = DLookup("LaborRate", "OperationsType", "[operationsID] = " & Operation.Value)
Cost.Value = DecTime.Value * LaborRate.Value
End If
End If
FormObjectsUpdate2 (RowNumber)
Set Operations = Nothing
Set Time = Nothing
Set DecTime = Nothing
Set LaborRate = Nothing
Set Cost = Nothing
End Function
Finally this is how my After update events look per control. I post just the first three not all 21 to save space.
Private Sub cb_op1_AfterUpdate()
OperationsUpdate (1)
End Sub
Private Sub cb_op2_AfterUpdate()
OperationsUpdate (2)
End Sub
Private Sub cb_op3_AfterUpdate()
OperationsUpdate (3)
End Sub
I just posted the function and the code for the first column operations all the other after update events are now having the same issues too.
I need to create a function that by the variable "number" goes to specify the number of the control that I've to change color.
Private Function match_color(partita, number)
If partita = "W" Then
MetroTile1.BackColor = Color.Green 'this is a specific control
ElseIf partita = "D" Then
ElseIf partita = "L" Then
End If
End Function
My goal is for example to access the control number 2, so I call the match_color function:
match_color("D",2)
and the number of control to change color is MetroTile2.BackColor = Color...
I don't know if I have made clear the idea, but simply is the variable "number" that specifies the number of the control to which change color.
Why does your business logic depend on the number that a control has in it's parent control? That's pointless and error-prone. Having said that, you could use Controls.Find:
Dim controls = Me.Controls.Find("MetroTile" & number, True) ' False if not recursive
If controls.Length > 0 Then
controls(0).BackColor = Color.Green ' or use a loop if you expect multiple
End If
In my program I have to reference different dynamically created buttons and they are stored in an array of records. Depending on what FieldShow is equal to, one of three FlowLayoutPanels are visible, which contain the buttons.
Private Function GetFields(i As Integer) As LoadingTemplate
Dim TempFields As LoadingTemplate
If FieldShow = 0 Then
TempFields.B = Study(i)
ElseIf FieldShow = 1 Then
TempFields.B = Task(i)
ElseIf FieldShow = 2 Then
TempFields.B = Note(i)
End If
Return TempFields
End Function
TempFields.B.RefBtn, if used here, then shows the button that is being returned, But if elsewhere I put
GetFields(x).B.RefBtn
with an appropriate value for X, it sometimes doesn't return things. Is there an easier way of doing this?
Thanks,
Henry