How to Simplify MS Access Form Searches Using Class Modules and Collections to Pair Text Boxes and Option Groups for Efficient SQL Query Generation

Deleted

New member
Local time
Today, 22:49
Joined
Dec 1, 2025
Messages
129

Rediscovering the Joy of Programming​

I haven’t been this absorbed in programming since my early days—back when I first discovered the magic of assigning objects to object variables and unlocking all kinds of possibilities in code.

For years I dabbled with class modules, but I never found a truly practical use for them… until now.

I almost said I couldn’t have done it without ChatGPT, but the truth is I probably could have—it just would have taken me a week instead of a couple of evenings.

One of the things I enjoy most is walking through objects with a For…Next loop and operating on a set of them simultaneously. Recently, I had a situation on a form involving a pair of controls: a TextBox and an OptionGroup.

  • The TextBox provides the search term.
  • The OptionGroup defines the type of search:
    • Option 1: Ends with → LIKE 'abc*'
    • Option 2: Contains → LIKE '*abc*'
    • Option 3: Starts with → LIKE '*abc'
    • Option 4: Null → [Field] IS NULL
    • Option 5: Exact match → = 'abc'

Naming Convention Evolution​

Originally, I relied on a custom naming convention to match controls. Later, I realized it was far more logical to use the Tag property. By storing the field name in both the TextBox and OptionGroup tags, I could easily link each pair together.

The code to walk through collections of objects is straightforward once you get the hang of it, but it often meant reusing the same boilerplate logic—lots of copy and paste.

Then came the breakthrough: ChatGPT suggested putting them into a collection. That reminded me of a thread I’d read years ago where Mark mentioned how often he used collections. Digging deeper, I realized I could go one step further: build a class module to hold the details of each object, store them in a collection, and expose a custom property to manage them.


Why the Class Module Works​

  • Encapsulation: The class module bundles the TextBox and OptionGroup into a single entity.
  • Simplicity: I no longer have to handle them separately.
  • Maintainability: The code becomes cleaner, shorter, and easier to reuse.

Old Code (Verbose)​

Code:
Dim ctlTxt As Control
Dim ctlOpt As Control
Dim intTxtPrefixLen As Integer
Dim intOptPrefixLen As Integer

intTxtPrefixLen = Len(conTxtPrefix)
intOptPrefixLen = Len(conOptPreFix)

For Each ctlTxt In Me.Controls
    If ctlTxt.ControlType = acTextBox Then
        If Left(ctlTxt.Name, intTxtPrefixLen) = conTxtPrefix Then
            ctlTxt.Value = ""
        End If
    End If
    For Each ctlOpt In Me.Controls
        If ctlOpt.ControlType = acOptionGroup Then
            If Right(ctlOpt.Name, Len(ctlOpt.Name) - intOptPrefixLen) = ctlTxt.Name Then
                ctlOpt.Value = 1
            End If
        End If
    Next ctlOpt
Next ctlTxt

New Code (Elegant)​

Code:
Dim ctrlCriteria As clsSearchCriteria

For Each ctrlCriteria In Me.SearchCriteriaCollection
    ctrlCriteria.TextBox.Value = ""        ' Clear the TextBox
    ctrlCriteria.OptionGroup.Value = 1     ' Reset to first option
Next ctrlCriteria

The Payoff​

  • Code is shorter, tidier, and easier to read.
  • Reuse is effortless across multiple TextBox/OptionGroup pairs.
  • Encapsulation means I can treat each pair as a single object.
This experience reminded me why I fell in love with programming in the first place: the thrill of discovering a smarter, cleaner way to solve a problem.
 
Last edited by a moderator:
I know how you feel Tony.
I am even looking at refreshing myself in COBOL, but on a PC and not a mainframe, just to keep my brain working. :)
 
I’m playing with html/css/javascript
 
I know how you feel Tony.
I am even looking at refreshing myself in COBOL, but on a PC and not a mainframe, just to keep my brain working. :)

Hi Paul, I think you're onto something there! From what I hear, decent COBOL programmers are becoming pretty rare these days, especially with so many legacy systems still running in industries like banking. You could end up landing a really profitable gig if you refresh those skills. Smart move keeping the brain ticking over with COBOL!"
 
No, at 70 years of age, I am now retired. Plus GCOS7 COBOL is different from IBM/ICL COBOL :-)
I know, as I had to teach ICL people. :)
Mind you, I did love GCOS7. :)

I did a fair bit in financial systems for banks and building societies as you say.
 
I’m playing with html/css/javascript
Hi Chris,
I noticed your recent post where you built an HTML interface for Microsoft Access, interesting stuff! I'd love to hear more about what you're doing with it. If you could keep us updated on your progress, that would be awesome! Or maybe it's time for another pint or two, and a chat, before the weather gets even worse!
 
I'm thinking two plus two makes four...?
Both of you seem to have ventured into some interesting coding projects, stepping outside your usual comfort zones. I wonder if it's thanks to the helpfulness of Chatty, or in Paul's case, maybe he's finally had enough of jigsaw puzzles!
 
Well TBH I was looking at doing a free course with Rocket (which used to be MicroFocus apparently), but having a devil fo a job getting the visual studio that is mentioned in the course. :-( So much so, I am thinking 'stuff it' . :)
 
Yes. I have a version on my laptop, which is nothing like the version in the course.
I am going to go looking again when I have time.
 
Do you mean visual studio code, the Microsoft IDE?
Just being pedantic: Visual Studio != Visual Studio Code

Visual Studio - grossly bloated IDE that is Windows only

Visual Studio Code - text editor on steroids that can be used as a basic IDE with appropriate plugins, and is cross-platform.
 
to keep my brain working
I have been meaning to ask how you got on with that "OK Google" monstrosity?

Are you finding it a help? Or did it drive you mad, as it did me and my dog?
 
Oh, I bought a few more, before moving on to Alexa's.
They all sit side by side like cousins. 😀
 
If you are starting out working with custom classes, note this debugger setting...

s0.png


If this is not set, the debugger will not break at the error in your custom class, it will break at the line making the call in the consumer.
 
Now I remember a thread a while back where Mark said that he often uses collections (If I recall correctly)... Further interrogation of ChatGPT led to the idea of building a class module to hold details of the object and a collection to retain the objects, and a custom property to fill the collection.
Can you or @MarkK share a simple file (or a link to the thread) to show how you did it?

I normally use a property in my forms instead of a collection.

Thanks.
 
Can you or @MarkK share a simple file (or a link to the thread) to show how you did it?

Looking back through my notes I found a record of a conversation I had with chatty, and it was nearly a year ago so bear in mind, chatty's faculties weren't quite so good then!

You said:

The following code loads a collection of option groups and a collection of textbooks is into a collection...


Private opts_ As VBA.Collection
Private srch_ As VBA.Collection

Private Property Get OptionGroups() As VBA.Collection
' lazy loads options group controls into a collection
If opts_ Is Nothing Then
Set opts_ = New VBA.Collection
opts_.Add Me.opttxtsDepartment
opts_.Add Me.opttxtsDescription
opts_.Add Me.opttxtsProduct
End If
Set OptionGroups = opts_
End Property

Private Property Get SearchTextBoxes() As VBA.Collection
' lazy loads search textboxes, keyed by name
If srch_ Is Nothing Then
Set srch_ = New VBA.Collection
srch_.Add Me.txtsDepartment, "Department"
srch_.Add Me.txtsDescription, "Description"
srch_.Add Me.txtsProduct, "Product"
End If
Set SearchTextBoxes = srch_
End Property

It was written by somebody else who is obviously a much better programmer than me!

But I'm puzzled as to why the option groups only reference the option object:- opts_.Add Me.opttxtsDepartment

But in the case of the text boxes there are like two parameters?

srch_.Add Me.txtsDepartment, "Department"

Can you explain why Mark has done that

ChatGPT said:

No problem at all! Let me break it down for you in a way that makes sense.

In the code, Mark is working with two different collections: one for Option Groups (opts_) and another for Search TextBoxes (srch_). The key distinction is how these collections are being used, which affects why he writes them differently.

1. Option Groups (opts_):

When adding items to the opts_ collection, Mark is just adding the controls themselves (i.e., Me.opttxtsDepartment, Me.opttxtsDescription, etc.). These are Option Group controls that don’t need to be "keyed" by any particular identifier. In other words, he is simply adding these controls to the collection without any label or key because he doesn't need to reference them by a name later. He's only storing the controls.

vba
Copy code
opts_.Add Me.opttxtsDepartment ' Adds the Option Group control itself


In this case, Mark expects to work with these option controls directly, probably by looping through them or accessing them one by one, without needing to look them up by a specific name.

2. Search TextBoxes (srch_):

In the case of the search textboxes, Mark adds both the control (Me.txtsDepartment) and a key ("Department"). The key is a string that represents an identifier for each textbox control, making it easier to access a specific textbox later by using this key.

vba
Copy code
srch_.Add Me.txtsDepartment, "Department" ' Adds the TextBox with a "Department" key


Here’s why the two parameters are needed in this case:

The first parameter (Me.txtsDepartment) is the textbox control itself, just like in the Option Groups collection.
The second parameter ("Department") is the key, a string that represents the specific textbox. This allows Mark to retrieve a textbox from the collection by name later on, like this:
vba
Copy code
Set txtBox = srch_("Department")


So, the key difference between the two collections is that the Search TextBoxes collection (srch_) is keyed, meaning you can retrieve textboxes by their names (like "Department", "Product", etc.), while the Option Groups collection (opts_) is just a list of controls with no names attached.

Why the Difference?

For Option Groups: Mark probably doesn't need to refer to them by name. He might iterate through them or treat them as a list, so a simple collection of controls works just fine.

For Search TextBoxes: Mark might need to refer to a specific textbox by its name (e.g., "Department"), so he uses a keyed collection to make this easier and more efficient.

💡 Takeaway:

Simple Collection (opts_): Use when you just need a list of controls without needing to identify them by name.
Keyed Collection (srch_): Use when you want to access specific controls using a unique identifier (like "Department").

I hope this clears it up! Feel free to ask more if you’re still curious about any part of this.

You said:
Where's your help a few days ago I did it in a slightly different way:-

Private collTextBoxes As Collection
Private collOptionGroups As Collection


And the form load event fills the collections

Private Sub Form_Load()
Set collTextBoxes = New Collection
Set collOptionGroups = New Collection

' Populate collections here
Dim ctrl As Control
For Each ctrl In Me.Controls
If TypeOf ctrl Is TextBox And Left(ctrl.Name, Len(conTxtPrefix)) = conTxtPrefix Then
collTextBoxes.Add ctrl
ElseIf TypeOf ctrl Is OptionGroup And Left(ctrl.Name, Len(conOptPreFix)) = conOptPreFix Then
collOptionGroups.Add ctrl
End If
Next ctrl

Call fFillSubFrm
End Sub 'Form_Load

So I was wondering could that idea here loading the collections in the form load event could that be transferred into the property and do that within the property?

Now I've just realized that means that the property would probably have to load all the controls every time it was called if we do it that way?

Unless of poor course and less of course the property can be made to keep its value after its first iterations through the code?

Does that make sense
ChatGPT said:

Yes, that absolutely makes sense! Let's walk through the idea of moving the logic from your Form_Load event into the property while keeping the collection persistent after its first load. This is totally doable, and you're right to think that we can lazy load the collections into the property, just like in Mark's original approach. I'll explain how that would work.
 
If you are starting out working with custom classes, note this debugger setting...

View attachment 116654

If this is not set, the debugger will not break at the error in your custom class, it will break at the line making the call in the consumer.
Thank you Mark. ATM, an error stops me even closing the form with @cheekybuddha's code, so I have to kill Access in task manager.
 

Users who are viewing this thread

Back
Top Bottom