Such a simple question, but I cannot find the answer (Google, MS help, SO):
How can I check by VBA whether an unbound checkbox on an Access form is checked by the user or not? Can't find the right property.
UPDATE:
I used this code after the suggestions of #HansUp and #RC:
Private Sub CmdTest_Click()
MsgBox "Check1.Value = " & Me.Check1.Value
MsgBox "Check2.Value = " & Me.Check2.Value
End Sub
Private Sub Form_Load()
Me.Check1.Value = 25
Me.Check2.Value = 50
End Sub
2nd UPDATE:
The code should be this (thanks to #David-W-Fenton):
Private Sub CmdTest_Click()
If Me.Check1 = True Then
MsgBox "Check1 IS CHECKED"
Else
MsgBox "Check1 IS NOT CHECKED"
End If
If Me.Check2 = True Then
MsgBox "Check2 IS CHECKED"
Else
MsgBox "Check2 IS NOT CHECKED"
End If
End Sub
Private Sub Form_Load()
' set first checkbox default checked
Me.Check1.Value = True
' set second checkbox default unchecked
Me.Check2.Value = False
End Sub
Checkboxes are a control type designed for one purpose: to ensure valid entry of Boolean values.
In Access, there are two types:
2-state -- can be checked or unchecked, but not Null. Values are True (checked) or False (unchecked). In Access and VBA, the value of True is -1 and the value of False is 0. For portability with environments that use 1 for True, you can always test for False or Not False, since False is the value 0 for all environments I know of.
3-state -- like the 2-state, but can be Null. Clicking it cycles through True/False/Null. This is for binding to an integer field that allows Nulls. It is of no use with a Boolean field, since it can never be Null.
Minor quibble with the answers:
There is almost never a need to use the .Value property of an Access control, as it's the default property. These two are equivalent:
?Me!MyCheckBox.Value
?Me!MyCheckBox
The only gotcha here is that it's important to be careful that you don't create implicit references when testing the value of a checkbox. Instead of this:
If Me!MyCheckBox Then
...write one of these options:
If (Me!MyCheckBox) Then ' forces evaluation of the control
If Me!MyCheckBox = True Then
If (Me!MyCheckBox = True) Then
If (Me!MyCheckBox = Not False) Then
Likewise, when writing subroutines or functions that get values from a Boolean control, always declare your Boolean parameters as ByVal unless you actually want to manipulate the control. In that case, your parameter's data type should be an Access control and not a Boolean value. Anything else runs the risk of implicit references.
Last of all, if you set the value of a checkbox in code, you can actually set it to any number, not just 0 and -1, but any number other than 0 is treated as True (because it's Not False). While you might use that kind of thing in an HTML form, it's not proper UI design for an Access app, as there's no way for the user to be able to see what value is actually be stored in the control, which defeats the purpose of choosing it for editing your data.
Check on yourCheckBox.Value ?
Related
I am seeing behaviour regarding checkboxes on a form which seems really weird, and I'm wondering if anyone else has come across it and can explain it.
Here's the form, which is bound to a table called FrequencyCodes:
Although the form is bound, the checkboxes are unbound. On the Form's load event they are populated by a procedure which reads a comma-separated string (in the column "CleaningDays") of numbers from 1-7, checking boxes appropriately. Here's that code:
Dim ctl As Control
For Each ctl In Me.Controls
If TypeOf ctl Is CheckBox Then
ctl.Value = InStr(1, Me.CleaningDays & ",", Right(ctl.Name, 1) & ",")
End If
Next ctl
The idea is that if a pattern of "One or more times per week" is chosen, the specific days can then be selected. For reasons of visual consistency with the option buttons above (for the cleaning pattern), I added an option group control to group the checkboxes together visually. I added the checkboxes, then so that I could select multiple options (which obviously isn't possible if they're part of an Option Group, I cut the checkboxes from the form, pasted them elsewhere on the form and then dragged them back into position. This resulted in a set of "standard" checkboxes, with possible values of true or false, rather than option values of 1 - 7 or whatever, had they been part of the option group. Here's the property sheet for one of them:
I then created code which, on the Click event of the OK button, loops through the checkboxes, and by using the last character of their names (they're called chk1 - chk7) builds a comma-separated list of the days when cleaning happens.
Here's the code:
Dim ctl As Control
Dim Output As String
For Each ctl In Me.Controls
If TypeOf ctl Is CheckBox
If (ctl = True) Then
Output = Output & Right(ctl.Name, 1) & ","
End If
End If
Next ctl
If Output <> vbNullString Then
Debug.Print "String calculated was " & Left(Output, Len(Output) - 1)
ReadCheckBoxes = Left(Output, Len(Output) - 1)
Else
ReadCheckBoxes = vbNullString
End If
The form wasn't working as expected, so I did some testing. The checkboxes weren't seeming to return Booleans (or 1 and 0) as expected.
You can see from the screenshot above that in this particular test, I'd selected options for Monday - Friday (chk2 - chk6 should have a value of true).
However, here's what I found from doing some testing in the immediate window:
? chk1
0
?chk2
-1
?chk3
-1
?chk4
1
? chk5
-1
?chk6
3
?chk7
0
Now, I know that any non-zero value equates to true, and that therefore these values should work. But they weren't. I was finding that on click on OK, only changed values would be recorded correctly - so, if, when the form was loaded, Monday - Friday were ticked, and I then tick Saturday before clicking OK, only chk7 (Saturday) would be recorded as being selected.
Can anyone explain this behaviour to me? I can't see the OptionValue property which I'd expect to see if these checkboxes were still part of an option group, yet this seems to be the value being returned.
Thank you!
When you set the checkboxes values, you don't set True or False, because InStr() returns the string position.
I suggest this to convert the result into a boolean:
ctl.Value = (InStr(1, Me.CleaningDays & ",", Right(ctl.Name, 1) & ",") > 0)
And when reading them, to be on the safe side:
If (ctl.Value <> False) Then
MS ACCESS 2007
VBA CODE BUILDER
I am able to show a MsgBox in VBA code when a Tab is selected with
Private Sub TabCtl34_Change()
If Me.TabCtl34.Value = 1 Then 'First Page
MsgBox "Hi"
End If
End Sub
But I also want to check if the second tab is selected and a field(Name) on the form IS NULL (not on tab), msgbox or cancel event to require Name to be entered before they see the second tab.
When I add in:
Private Sub TabCtl34_Change()
If Me.TabCtl34.Value = 1 AND [FORMS]![FORMNAME]![NAME] IS NULL Then
MsgBox "Hi"
End If
End Sub
It just goes directly to the second tab even if the name is null. How do i write the vba code so it can do what I want?
IS NULL is for use in query expressions, from VBA use the IsNull() VBA function.
If Me.TabCtl34.Value = 1 AND IsNull([FORMS]![FORMNAME]![NAME]) Then
As you are running this from the form's module you can use Me to refer to the current form-instance:
If Me.TabCtl34.Value = 1 AND IsNull(Me.[NAME]) Then
You should also consider that the value may be an empty string, rather than NULL. You can combine both checks using:
If Me.TabCtl34.Value = 1 And Len(Me.[NAME].Value & "") = 0 Then
Concatenating the empty string "" coerces a NULL value to a string.
(It is preferable to explicitly identify the property Value rather than assume it as the default property.)
I would like to know the proper syntax to write a string which will activate and de-activate the record selectors on subform 'frmEffortImpact' located on the main form 'frmProjectCharter01'. Unfortunately I continue to get an error message "properties or methods not supported by object". This is the code i am currently using:
Private Sub cmdAddImpacts_Click()
If Me.AllowAdditions = True Then
Forms![frmprojectcharter01]![frmEffortImpact].RecordSelectors = False
ElseIf Me.AllowAdditions = False Then
Forms![frmprojectcharter01]![frmEffortImpact].RecordSelectors = True
End If
With Forms![frmprojectcharter01]![frmEffortImpact] you are reaching the subform control (which has properties like SourceObject and LinkMasterFields). To get the normal Form properties of the form being used as a subform, you need to access the .Form property of the subform control.
Forms![frmprojectcharter01]![frmEffortImpact].Form.RecordSelectors = False
Then you can reach .RecordSelectors and others.
im trying to check if a number is a text or number in a banking system. If the value is incorrect it should erase and send an error message, but my code isnt working at all... can someone help me? here is the code:
Private Sub TextBox1_Change()
name = TextBox1
If Application.IsText(name) = True Then
IsText = True
Else
MsgBox "Insert only words"
Selection.name.Delete
End If
End Sub
I think you should be using name = TextBox1.Text instead. It's probably giving you an error on that line.
Also, you may want to wait until the user is finished typing the response, I believe the changed event will run each time a character is pressed. The AfterUpdate will run after you tab or click away from the textbox.
And really, instead of deleting the response (which I don't think will work), you should simply set the textbox blank back to an empty string.
Private Sub TextBox1_AfterUpdate()
If Not MyIsANumber(TextBox1.Text) Then
MsgBox ("It's Text")
Else
TextBox1.Text = ""
End If
End Sub
Function MyIsANumber(str As String) As Boolean
For i = 1 To Len(str)
If IsNumeric(Mid(str, i, 1)) Then
MyIsANumber = True
Exit Function
End If
Next
MyIsANumber = False
End Function
I'm sure the code could be structured better, but there's something along the lines of what you need. In this case, it just wipes the textbox if there is a number entered. Obviously, things will need to be the opposite for your textbox that you want to contain a number.
Have you considered the vartype() function? https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/vartype-function
Im trying to pass the name of a global variable to a sub routine and would like to know how to reference it. For example I could do the below with a control:
Private Sub passCtrlName(ctlName as String)
Me.Controls(ctlName) = "Whatever"
End Sub
Edit:
For Example
Public imGlobVar As String
Public Sub passGlobVar(frm as Form, ctlName as String, globVar as String)
frm.Controls(ctlName) = globVar
End sub
And call it as
Private Sub imaButton_Click()
imGlobVar = "something"
Call passGlobVar(Me , txtBox1, imGlobVar)
End sub
2nd Edit:
It seems that I could most definitely be barking up the wrong tree here, so I will explain what I'm trying to achieve.
I have a form that has textboxes for the users (risk) address, with a checkbox at the top that lets the user select that this address is the same as the 'contact' details already on the system, and the textboxes are locked.
Populating the textboxes is fine and works. What I use the global variables for is to improve usability (albeit slightly).
The user can add new details, and if they hit the checkbox 'make same as contact' the details that they have entered are stored in the global variables, one for each control.
If the user has made a mistake by hitting the checkbox, they haven't lost these value, and by unchecking the box the entered values are returned.
I hoped to create a sub routine where I could pass the name of the global variable and control and calling this routine, as opposed to writing it out for each control.
I have a feeling that I could be using the wrong technique to achieve my goals. But in answer to my original question, it appears that you can not pass global variables to sub routines in the manner that I wished.
You do not need to pass global variables, you can simply refer to them by name. Note that global variables are reset if an unhandled error occurs.
In http://msdn.microsoft.com/en-us/library/dd897495(office.12).aspx you will find a section on Scope and Lifetime of Variables and Constants.
In a module:
Option Explicit
Public glbVarName As String
Const MyConstant=123
Sub InitVar
glbVarName="Something"
End Sub
Any other module, includeing a form's class module:
Sub SomeSub
MsgBox glbVarName
SomeVar=2+MyConstant
End Sub
If you're asking if you can dynamically reference global variables using a string containing the variable name the answer is no. You could use a single global array and pass the index, which would allow you to dynamically reference an element of the array.
[Edit]
In response to the clarification in the question: You could just save the value of each control to its Tag property when the user checks the checkbox. Then, if the user unchecks the checkbox, you can just loop over your controls and assign the value from the Tag back to the Value of the control.
You could store the values from your controls in a Dictionary object, using the control names as the dictionary keys. Then you can retrieve the value for each control based on the control's name.
Option Compare Database
Option Explicit
Const cstrMyControls As String = "Text0,Text2,Text4,Text6"
Dim objDict As Object
Private Sub chkToggle_Click()
If Me.chkToggle = True Then
Call SaveValues
Else
Call RestoreValues
End If
End Sub
Private Sub SaveValues()
Dim varControls As Variant
Dim i As Long
Set objDict = Nothing 'discard previous saved values '
Set objDict = CreateObject("Scripting.Dictionary")
varControls = Split(cstrMyControls, ",")
For i = 0 To UBound(varControls)
objDict.Add varControls(i), Me.Controls(varControls(i)).Value
Next i
End Sub
Private Sub RestoreValues()
Dim varControls As Variant
Dim i As Long
If objDict Is Nothing Then
'MsgBox "No values to restore." '
Else
varControls = objDict.keys()
For i = 0 To UBound(varControls)
Me.Controls(varControls(i)).Value = objDict(varControls(i))
Next i
End If
End Sub
I use additional field in table - name cancel - of course boolean - when i'm not sure if contents of fields will be valid I set it true. If this field will be true by the end - then I clean up (it may be all record or some fileds of course). Very easy.