Here's the short version: Need help figuring out why a combobox on a form is misbehaving. The combobox loads with a rowsource query, and the form load event procedure writes a default text in the combobox as a sort of user input prompt that isn't in the query list but seems to show up just fine when the form loads. When I change the rowsource query through code in another event procedure I can no longer write the same default text into the combobox. If this is because the default value isn't part of the new rowsource query list (which is the same query but with a WHERE clause to filter some of the options), then why can I do this before changing the rowsource even though it also doesn't match any records among the combobox's default rowsource?
Here's the long version:
I'm working on a construction cost database and modeling tool, and the form in question is an intake form for new conceptual projects with a few textbox and combobox fields for user input.
For aesthetic reasons I want to show default values for each input field in grey as a sort of user instruction prompt, and then change these to black as the fields are completed. There's code in the Form_Load() event procedure which writes the default value in all the controls, and also changes the text color to grey. The GotFocus() event procedure for control then changes the color to black and writes the value to vbNullString so the user doesn't have to delete the previously written default value. Then after the user moves on to another field the LostFocus() event procedure tests if a change has been made, either by typing into the text box in question or selecting from the list if it's a combo box, and will reset the default value as well as change color back to grey if no change has been made (or leave as is in black color if a change was made). This much of the code seems to be working fine.
Here's the issue:
One of the comboboxes asks for 'Space Type' and another one for 'Space Subtype'. When the user selects a particular space type for the project, I want to filter the space subtype list options to show only those related to that space type. I've done this by rewriting the cmbSpaceSubtype.RowSource query within the cmbSpaceType_Change() event procedure, and this also seems to be working fine. The problem is after the row source query is changed through this event procedure, it seems I can no longer rewrite the cmbSpaceSubtype text to the default value that I'd like to show until the user makes a selection for that field. I would think this is obviously because the default value I'm using is not an option on the query list that the row source now points to. But if that's the case then why can I use an identical line of code to write in the same default value through the Form_Load() event procedure, even though the default value also not an option on the row source for that combobox when the form is loading?
Here's a link to the Access file: [https://app.e-builder.net/public/publicLanding.aspx?QS=b3a5c010645942a9881b361dae7433ae][1]
Here's an excerpt of the vba code:
Option Compare Database
Private Const sListDefault As String = "Select from list"
Private Sub Form_Load()
With Me
Let .cmbSpaceSubtype = sListDefault
Let .cmbSpaceType = sListDefault
End With
End Sub
Private Sub cmbSpaceSubtype_GotFocus()
With Me.cmbSpaceSubtype
If .Text = sListDefault Then
Let .Value = vbNullString
Let .ForeColor = vbBlack
End If
End With
End Sub
Private Sub cmbSpaceSubtype_LostFocus()
With Me.cmbSpaceSubtype
If .Text = vbNullString Or IsNull(Me.cmbSpaceSubtype) Then
Let Me.cmbSpaceSubtype = sListDefault
Let .ForeColor = vbTextLight
End If
End With
End Sub
Private Sub cmbSpaceType_Change()
With Me.cmbSpaceSubtype
If Me.cmbSpaceType.Text = sListDefault Then
Let .RowSource = "SELECT [ID], [Space Subtype] FROM tblSpaceSubtypes ORDER BY [Space Subtype];"
Else
Let .RowSource = "SELECT [ID], [Space Subtype] " _
& "FROM tblSpaceSubtypes WHERE [Space Type]=" & Me.cmbSpaceType.Value & " ORDER BY [Space Subtype];"
End If
Let Me.cmbSpaceSubtype = sListDefault
Call .SetFocus
Let .ForeColor = vbTextLight
End With
End Sub
Private Sub cmbSpaceType_GotFocus()
With Me.cmbSpaceType
If .Text = sListDefault Then
Let .Value = vbNullString
Let .ForeColor = vbBlack
End If
End With
End Sub
Private Sub cmbSpaceType_LostFocus()
With Me.cmbSpaceType
If .Text = vbNullString Or IsNull(Me.cmbSpaceType) Then
Let .Value = sListDefault
Let .ForeColor = vbTextLight
End If
End With
End Sub
Finally figured it out ... resetting the combo box to a default value after changing the rowsource did execute properly but I wasn't seeing the default value on the form because it's a multicolumn row source and the bound column was width 0, so the value was hidden.
Related
pretty simple question here in scope.
Question:
Wondering If I would be able to hide the tabs of a form based off the values of a table's fields.
I have been reading the 2019 Access Bible and so far it is still unclear to me how I would write the VBA module to constantly be running. Im asking the question a little early in my attempts, but hoping I can ask this well enough to get a head start.
I dont quite understand the execution model of VBA for access yet. I have prior expierence coding but this will be my 1st time in access. Just looking for a little help on how to write the function scope. You see below that I think it should be "Main" something, as I want it to run whenever in form view. Like I know how to write Private sub functions to respond to a button click. But not for a function that just runs in the background of the form.
I guess the real question is when to execute? Right? Any suggestions?
I was thinking something along the line of this below.
Main function()
If Me.FieldProcess_Water = "1" Then
Me.TabProcess_Water.Visible = True
Else
Me.TabProcess_Water.Visible = False
End If
End Sub
This requires some setup to reduce redundant code but should do what you want.
First you'll need your checkbox names and page names to be similar. In my example I have the page names as Tab_Name and the checkboxes as just Name. eg. Tab_Process Water and Process Water.
Then Create a sub called Form_Current() in the form's code-behind.
Private Sub Form_Current()
Dim chk As Control
For Each chk In Me.Controls
If chk.ControlType = acCheckBox Then
If chk = False Then
'Change TabCtl0 to whatever your's is called
Me.TabCtl0.Pages("Tab_" & chk.Name).Visible = False
Else
Me.TabCtl0.Pages("Tab_" & chk.Name).Visible = True
End If
End If
Next
End Sub
This will iterate through the current record's checkboxes and toggle it's respective tab's visibility.
To have the CheckBox update the tabs as they are clicked:
Private Sub Form_Load()
Dim chk As Control
Dim prop As Variant
For Each chk In Me.Controls
If chk.ControlType = acCheckBox Then
chk.OnClick = "=Check_Click()"
End If
Next
End Sub
This will assign a command to each checkbox.
Dim caller As String
caller = Me.ActiveControl.Name
If Me.ActiveControl.Value = False Then
Me.TabCtl0.Pages("Tab_" & caller).Visible = False
Else
Me.TabCtl0.Pages("Tab_" & caller).Visible = True
End If
This will hide the relevant tabs.
I have a form in MS Access with multiple checkboxes which I want to use to fill up one textbox. If one of the checkboxes gets unchecked, I want its value to be deleted from the textbox without deleting other values. I'm new at using Access and coding in VBA (been reading ebooks for the past 3 weeks) and although I've tried to do research online it's been difficult for me to find the right code.
This is what I have so far:
First code found
Private Sub cb_click()
If Me.cb1 = True Then
Me.txtComentarios.Value = "INACTIVO;"
Else
Me.txtComentarios.Value = Null
End If
End Sub
Second code found
Private Sub cb2_Click()
If Me.cb2 = -1 Then
Me.[txtComentarios] = [txtComentarios] & "DISCREPANCIA"
Else
Me.[txtComentarios] = ""
End If
Exit Sub
End Sub
Also I would like for the checkboxes to fill the textbox in the same order the chechboxes are displayed.
Ex.
cb1; cb2; cb3
If, cb2 gets unchecked and its value gets deleted, I should have "cb1; cb3" but if I re-check cb2 I should get "cb1; cb2; cb3" again.
I just hope someone could guide me in. Thank you in advance.
Luz
You don't need events for each checkbox. Just create one procedure, which creates full text depending on checkboxes state and puts this text to the textbox. To call this function after each click on checkbox set After Update property of all checkboxes to =MyFunctionToUpdateTextbox instead of [Event Procedure]
Private Function MyFunctionToUpdateTextbox()
Dim strText As String
If Me.cb1 = True Then
strText = strText & "INACTIVO;"
End If
If Me.cb2 = True Then
strText = strText & "DISCREPANCIA;"
End If
If Me.cb3 = True Then
strText = strText & "Text for cb3"
End If
Me.txtComentarios = strText
End Function
C, Thank you for your input and encouragement! I have changed my form and script slightly, I am afraid I kept the if then statement as I am comfortable with the formatting. The script now works when the 'On Open'event runs.
Private Sub Form_Open(Cancel As Integer)
Me.ChkAlbumNotes.SetFocus
If Me.ChkAlbumNotes.Value = False Then
Me.lblAlbumNotes.Visible = False
Me.txtAlbumNotes.Visible = False
Me.btnAlbumNotes.Visible = True
Else
Me.lblAlbumNotes.Visible = True
Me.txtAlbumNotes.Visible = True
Me.btnAlbumNotes.Visible = False
End If
Me.TrackName.SetFocus
If Me.TrackName = " " Then
Me.btnAddRecord.SetFocus
Else
Me.btnNextRecord.SetFocus
End If
End Sub
This is fine when the form opens for the first time but I have a set of navigation buttons that are installed by the application as Macros. I cannot add my script to the On_Click event when the button is clicked, as On_Click is linked to the Macro. Is there a way to incorporate the script from the On_Load process to the pre-defined macro? Or can you suggest a neater way to achieve my requirements which are;
When the form opens,a check is made for the existence of a false value in the checkbox
if the check box is set to false, then the Notes Text Box and label are hidden and the notes button is visible.
If the check box has a true value, then the Notes text box and label are made visible and the button is hidden.
On completion of the test I check the field Track Name
if this is empty, I assume I am at the last record and give the Add New Record button the focus
If Track Name is not empty, then focus is set to Next Record button
when this button is clicked, the next record page opens and the process starts again.
Many Thanks
Mike
You should use the Form_Current event instead of Form_Open . This fires on starting the form (2 times) and everytime you move to another record.
Private Sub Form_Current()
Me.lblAlbumNotes.Visible = Me.ChkAlbumNotes.Value
Me.txtAlbumNotes.Visible = Me.ChkAlbumNotes.Value
Me.btnAlbumNotes.Visible = Not Me.ChkAlbumNotes.Value
If Me.TrackName = "" Then ' I suggest If Me.TrackName = " " being a typo and you want to check if empty ( that's why you should use vbNullString instead of "")
Me.btnAddRecord.SetFocus
Else
Me.btnNextRecord.SetFocus
End If
End Sub
I have an access form that needs filling in daily by various people.
It's to document changes to a website and I currently have a combobox box set up for the various sections to state whether they are AMENDS, REVERTS or NO CHANGE.
I have set conditional formatting to then highlight these sections but am also trying to get it to work so that if the user chooses "NO CHANGE" then the data for that field copies over from the previous record.
I have set this up in the AfterUpdate code for the combobox, but nothing is happening, not even an error... can anyone help?
Private Sub COMBOBOX1_AfterUpdate()
If Me.COMBOBOX1 = 3 Then
Me.[FIELD_TO_CHANGE] = DLookup("[FIELD_TO_CHANGE]", "tb_TABLE", "[ID]=Forms![form_FORM]![ID]-1")
End If
End Sub
(Where 3 is the value of NO CHANGE in the combobox, and FIELD_TO_CHANGE, tb_TABLE and form_FORM being the names of the various elements)
Thanks!
First you should define your control COMBOBOX1, enter in Properties Window, define
COMBOBOX1.AfterUpdate = "[Event Procedure]"
then your Private Sub COMBOBOX1_AfterUpdate() will be taken into account. Error may occur and popup to you.
Then change the event handler like this to start:
Private Sub COMBOBOX1_AfterUpdate()
If Me.COMBOBOX1 = 3 Then
Me.[FIELD_TO_CHANGE] = DLookup("[FIELD_TO_CHANGE]", "tb_TABLE", "[ID]=" & (Me.[ID] - 1))
End If
End Sub
There will be many errors to correct before your form works...
Following on from my previous question.
A requirement from the customer is to have checkboxes on a report to disable rows of information on another sheet. The rows are defined as named ranges, formated by P_XXXXXX. The XXXXXX is a unique identifier that is also a field on the row so I can easily generate the range names on the fly.
The problem I am having is:
After clicking on the items and then closing the form Excel asks if we want to save. This is undersirable.
I need someway of registering a change event happening on my generated checkboxes. So if one or more changes I can run through and hide/unhide the relevant ranges.
My code for adding the checkboxes looks like:
' For each row...
' check box in column 17(=Q).
Dim lCenter As Long
lCenter = rngCurrent.Width / 4 ' not actual centre but close enough
With ActiveSheet.CheckBoxes.Add(rngCurrent.Left + lCenter, rngCurrent.Top - 2, rngCurrent.Width, rngCurrent.Height)
.Interior.ColorIndex = xlNone
.Caption = ""
End With
So how do you link a change in a checkbox with a sub/function?
Set the OnAction property of the Checkboxes object to the name of a sub you want to run whenever the checkbox is checked or unchecked.
Sub MakeCB()
With ActiveSheet.CheckBoxes.Add(ActiveCell.Left + 0, ActiveCell.Top - 2, ActiveCell.Width, ActiveCell.Height)
.Interior.ColorIndex = xlNone
.Caption = ""
.OnAction = "CheckboxChange"
End With
End Sub
Sub CheckboxChange()
MsgBox "change"
End Sub
I don't think there are any events available with the Excel.Checkbox control. Try using the MSForms checkbox instead. You'll need a reference to 'Microsoft Forms 2.0 Object Library' - it's not redistributeable, but if you're using VBA, then that's fine.
You can then do something like this, and handle the event in the usual way:
''class level
Private WithEvents m_Checkbox as MSForms.CheckBox
Public Sub MakeCheckbox()
Set m_Checkbox = Activesheet.OLEObjects.Add("Forms.Checkbox.1")
End Sub
Private Sub m_Checkbox_Click()
''Do stuff
End Sub
Obviously, you'll only be able to handle a set number of checkboxes this way - I would recommend creating a class to hold each checkbox.