Streamlining Form Module Code in Standalone Class Module.
Data Filter by Character and Sort on Form.
Version 1.0 of this Article was originally published in April 2009 and introduces a significant change in the Demo Application in Version 2.0. In this version, the Event Subroutines are executed from the standalone class module, rather than from the form module.
After realizing the advantages of Event Procedures Coding in Standalone Class Modules, I found it difficult to revert to the traditional, less organized, and time-consuming Form/Report Module VBA Coding procedures.
In the traditional coding style, to modify a specific event subroutine code in the Form Module, with various types of controls, several steps are typically required.
- Open the Form in Design View.
Select the required Control.
- Display its Property Sheet.
Select the specific Event Property.
- Click on the Build Button to open the Event Procedure.
Write/Modify the Code.
- Save the Form with the Code.
Open the Form in Normal View to test the change.
So, it typically involves eight steps to reach the specific event procedure code to write/edit and save the changes.
While it’s true that multiple event procedures can be modified consecutively once the form is open, steps 2 through 6 still need to be repeated to reach each specific event procedure code. This repetitive cycle can be tedious and time-consuming, as it’s often repeated numerous times throughout the coding process. Additionally, the user interface designing also requires a considerable amount of time and both these events take place side by side. Moreover, the Code that you developed in the Form Module is not reusable and leaves all of them in the Form Module forever, except for the Public Functions in the Standard Module of the Project.
If you’re a beginner VBA programmer, learning the language alongside user interface design is best accomplished through the traditional method. However, if you’re already an experienced developer, I recommend experimenting with the streamlined VBA event procedure coding in Standalone Class Modules to experience the difference compared to the traditional coding style. It can provide valuable insights and enhance your coding efficiency saving a tremendous amount of Project Development time. Besides that, the reusable VBA Code in the Standalone Class Module can be Exported into other Projects for reuse.
Streamlined event procedure coding involves more than just moving the code from the form module to the standalone class module. It's about organizing the event procedure code in a structured and concise manner, which promotes reusability without the need for duplicating code for multiple objects of the same type in the form module. This approach enhances code maintainability and reduces redundancy, resulting in a more efficient and manageable codebase.
Direct access to the Structured Event Subroutines in the Standalone Class Module eliminates the need to struggle with navigating through the form design view to reach a particular event subroutine. This direct access streamlines the development process, making it easier to locate and modify event procedures without the hassle of navigating through the form's design view.
Example of Structured Event Subroutine Coding:
The BeforeUpdate Event Procedure Code of several TextBoxes can be written within a single BeforeUpdate() Event Subroutine.
Private Sub txt_BeforeUpdate(Cancel As Integer) 'When the BeforeUpdate Event is captured the txt object will have 'the Name of the Object fired the Event Select Case txt.Name Case "Quantity" 'Code Case "UnitPrice" 'Code Case "SaleTax" ' Code Case . . . End Select End Sub
The seventh episode in this series of articles is a prime example of event subroutine code Reuse and illustrates an organized, structured approach to event procedure coding. By writing just one set of GotFocus and LostFocus Event Subroutines, you can efficiently manage the behavior of 25 or more text boxes on the form when they gain or lose focus. This example offers a straightforward demonstration of how to effectively implement the concept of streamlined event procedure coding in a standalone class module, emphasizing code reusability and reduced redundancy.
The Microsoft Access TextBoxes, Command Buttons, and other Controls' various Event-Defining Event-Firing, and Event-Capturing mechanisms, which form the foundation for Streamlined Event Subroutine Coding, are explored in detail in my presentation to the Access User Groups (Europe) on January 3, 2024. The Presentation's YouTube Video is available on Access User Groups (Europe)'s YouTube Channel, providing insights into the streamlined Event Subroutine coding in Standalone Class Modules. You can find the video here: Streamlined Event Procedure Coding in Standalone Class Module.
In our current project of 'Filter by Character and Sort', the Customers Form’s record source is derived from the CustomersQ query, which contains multiple records. To enhance user experience and efficiency, we’ll implement a technique that swiftly filters records by allowing users to type the first one or more characters from the customer’s selected Data Field. Utilizing the form’s filter settings, matching records will be quickly identified based on the characters typed into a text box control. This feature will streamline the process of locating specific customer records, improving overall usability.
The Customers Form Image-1 Normal Data View.
Customers Form Image-2 with Filtered Data.
The TextBox, highlighted with a yellow background, functions as the filter text input control. Above it, a Combo Box allows users to choose the field for text search; in this case, the Last Name field is selected. This will be used to locate matching data. As users type into the filter input TextBox, the system will match the beginning of the selected field value with the entered text and filter the records accordingly. This arrangement allows users to quickly and efficiently search for and filter records based on the starting character(s), making it easier to find specific names that meet the criteria provided.
In this example, three records are initially filtered, each starting with the letter 'G' in the Last Name field. When you type 'r' after 'G' in the filter control with the yellow background, the first record, which contains the letter 'o', no longer matches and disappears from the results. This dynamic filtering approach enables precise and efficient record retrieval, adjusting in real time based on user input. It helps users quickly find records that meet their search criteria.
When the Backspace key is pressed to delete the last character entered from the filter control TextBox, the data dynamically updates to reflect the change in filtering based on the remaining characters. The filter adjusts accordingly, showing records that meet the new criteria. If no characters remain in the filter control, the entire dataset reappears in the form's detail section, allowing users to view all records. This approach creates a seamless and intuitive filtering experience, with real-time updates that respond to user input.
The Cls_ObjInit Class Module VBA Code.
Option Compare Database Option Explicit Private WithEvents frm As Access.Form Private WithEvents txt As Access.TextBox Private WithEvents cmd As Access.CommandButton Private WithEvents cbo As Access.ComboBox Dim txt2Filter Public Property Get m_Frm() As Access.Form Set m_Frm = frm End Property Public Property Set m_Frm(ByRef vFrm As Access.Form) Set frm = vFrm Call Class_Init End Property Private Sub Class_Init() Const EP = "[Event Procedure]" Set txt = frm.FilterText Set cmd = frm.cmdClose Set cbo = frm.cboFields With frm .OnLoad = EP .OnUnload = EP End With With txt .OnKeyUp = EP End With With cmd .OnClick = EP End With With cbo .OnClick = EP End With End Sub Private Sub cbo_Click() frm.FilterText = "" txt2Filter = "" frm.Filter = "" frm.FilterText.SetFocus frm.FilterOn = False End Sub Private Sub txt_KeyUp(KeyCode As Integer, Shift As Integer) Dim C As Integer, sort As String Dim L As String On Error GoTo txt_KeyUp_Err C = KeyCode With frm Select Case C Case 8 'backspace key txt2Filter = Nz(![FilterText], "") If Len(txt2Filter) = 1 Or Len(txt2Filter) = 0 Then txt2Filter = "" .FilterOn = False ' remove filter frm.Recalc Else txt2Filter = Left(txt2Filter, Len(txt2Filter) - 1) 'delete the last character If Len(txt2Filter) = 0 Then .FilterOn = False ' remove filter Else 'set filter and enable .Filter = "[" & ![cboFields] & "]" & " like '" & txt2Filter & "*'" ![FilterText] = txt2Filter 'position cursor position at the end of the text If Len(!FilterText) > 0 Then .Section(acFooter).SetTabOrder ![FilterText].SelLength = Len(![FilterText]) SendKeys "{END}" 'position cursor at right end of text End If .FilterOn = True End If End If Case 37 'right arrow key, prevent text highlighting SendKeys "{END}" 'position cursor at right end of text Case 32, 48 To 57, 65 To 90, 97 To 122 'space, 0 to 9, A to Z, a to z keys txt2Filter = txt2Filter & Chr$(C) 'First letter of words to uppercase ![FilterText] = StrConv(txt2Filter, vbProperCase) SendKeys "{END}" GoSub SetFilter End Select End With txt_KeyUp_Exit: Exit Sub SetFilter: With frm .Refresh If Len(txt2Filter) = 0 Then .FilterOn = False ' remove filter Else 'set filter and enable .Filter = "[" & ![cboFields] & "]" & " like '" & txt2Filter & "*'" .FilterOn = True ' Set sort order sort = IIf(!Frame10 = 1, "ASC", "DESC") .OrderBy = "[" & !cboFields & "] " & sort .OrderByOn = True .Section(acFooter).SetTabOrder 'Form Footer Section Active 'position cursor at end of text ![FilterText].SelLength = Len(![FilterText]) SendKeys "{END}" End If End With Return txt_KeyUp_Err: MsgBox Err.Description, , "txt_KeyUp()" Resume txt_KeyUp_Exit End Sub Private Sub cmd_Click() DoCmd.Close acForm, frm.Name End Sub
There are three Controls in the Footer of the Form that fire simple Events that we need to capture and run simple Code, except the TextBox KeyUp() Event.
The Wrapper Class Object creation is not necessary in this case for TextBox, ComboBox, and Command Button because there is only one instance of these controls on the Form.
In the Global Declaration area, the main Object Instances are declared, qualified with the WithEvents Keyword to enable and capture certain Events and execute the Event Subroutines, in the Cls_ObjInit Class Module. Another Variant Type Variable txt2Filter is also declared in the global area followed by the Form Property procedures.
Next, the Class_Init() Subroutine is called from the Set m_Frm() Property Procedure after receiving the Form Object from the Form_Load() Subroutine in the Form Module.
Next, the txt, cmd, and cbo objects are assigned with the References of these controls on the Form.
Next, the Objects are enabled with the required Events.
The Combobox Click_Event selects a particular Field Name as the target field to filter the records. This Subroutine will reset the filter applied earlier.
The Command Button Click Event closes the Form.
The TextBox, where we enter the Filter Input text, fires the KeyUp() Event, and the valid Key Code received is identified and added to a String, character by character, and used as Filter Criteria at each step in the selected Field in the Combo Box.
The txt_KeyUp() Event Subroutine Code.
Private Sub txt_KeyUp(KeyCode As Integer, Shift As Integer) Dim C As Integer, sort As String Dim L As String On Error GoTo txt_KeyUp_Err C = KeyCode With frm Select Case C Case 8 'backspace key txt2Filter = Nz(![FilterText], "") If Len(txt2Filter) = 1 Or Len(txt2Filter) = 0 Then txt2Filter = "" .FilterOn = False ' remove filter frm.Recalc Else txt2Filter = Left(txt2Filter, Len(txt2Filter) - 1) 'delete the last character If Len(txt2Filter) = 0 Then .FilterOn = False ' remove filter Else 'set filter and enable .Filter = "[" & ![cboFields] & "]" & " like '" & txt2Filter & "*'" ![FilterText] = txt2Filter 'position cursor position at the end of the text If Len(!FilterText) > 0 Then .Section(acFooter).SetTabOrder ![FilterText].SelLength = Len(![FilterText]) SendKeys "{END}" 'position cursor at right end of text End If .FilterOn = True End If End If Case 37 'right arrow key, prevent text highlighting SendKeys "{END}" 'position cursor at right end of text Case 32, 48 To 57, 65 To 90, 97 To 122 'space, 0 to 9, A to Z, a to z keys txt2Filter = txt2Filter & Chr$(C) 'First letter of words to uppercase ![FilterText] = StrConv(txt2Filter, vbProperCase) SendKeys "{END}" GoSub SetFilter End Select End With txt_KeyUp_Exit: Exit Sub SetFilter: With frm .Refresh If Len(txt2Filter) = 0 Then .FilterOn = False ' remove filter Else 'set filter and enable .Filter = "[" & ![cboFields] & "]" & " like '" & txt2Filter & "*'" .FilterOn = True ' Set sort order sort = IIf(!Frame10 = 1, "ASC", "DESC") .OrderBy = "[" & !cboFields & "] " & sort .OrderByOn = True .Section(acFooter).SetTabOrder 'Form Footer Section Active 'position cursor at end of text ![FilterText].SelLength = Len(![FilterText]) SendKeys "{END}" End If End With Return txt_KeyUp_Err: MsgBox Err.Description, , "txt_KeyUp()" Resume txt_KeyUp_Exit End Sub
The Form Module Code.
Option Compare Database Option Explicit 'Global declaration Private obj As New Cls_ObjInit Private Sub Form_load() Set obj.m_Frm = Me Application.SetOption "Behavior Entering Field", 2 End Sub Private Sub Form_Unload(Cancel As Integer) Application.SetOption "Behavior Entering Field", 0 Set obj = Nothing End Sub
Filter By Character in ComboBox Items.
The above Screenshot is the second Form Customers_Combo implements the 'Filter By Character' in the Combobox Items. The KeyUP() Event Subroutine is almost the same as the first Form Filter method we saw earlier. A new Cbo_ObjInit Class Module is added for this Form. The Cbo_ObjInit Class Module VBA Code is given below:
Option Compare Database Option Explicit Private WithEvents frm As Access.Form Private WithEvents txt As Access.TextBox Private WithEvents cmd As Access.CommandButton Private cbo As Access.ComboBox Dim txt2Filter Public Property Get m_Frm() As Access.Form Set m_Frm = frm End Property Public Property Set m_Frm(ByRef vFrm As Access.Form) Set frm = vFrm Call Class_Init End Property Private Sub Class_Init() Const EP = "[Event Procedure]" Set txt = frm.FilterText Set cmd = frm.cmdExit Set cbo = frm.cboCust With frm .OnLoad = EP .OnUnload = EP End With With txt .OnKeyUp = EP End With With cmd .OnClick = EP End With End Sub Private Sub txt_KeyUp(KeyCode As Integer, Shift As Integer) Dim i As Integer Dim SQL As String Dim SQL1 As String Dim SQL2 As String On Error GoTo txtKeyUp_Err SQL = "SELECT CustomersQ.* FROM CustomersQ ORDER BY CustomersQ.[Last Name];" SQL1 = "SELECT CustomersQ.* FROM CustomersQ " SQL2 = "WHERE (((CustomersQ.[Last Name]) Like '" '"Gr*")); i = KeyCode Select Case i Case 8 'backspace key frm.Refresh If Len(txt2Filter) = 1 Or Len(txt2Filter) = 0 Then txt2Filter = "" Else txt2Filter = Left(txt2Filter, Len(txt2Filter) - 1) 'delete the last character End If GoSub SetFilter Case 37 'right arrow keys SendKeys "{END}" Case 32, 48 To 57, 65 To 90, 97 To 122 'space, 0 to 9, A to Z, a to z keys txt2Filter = txt2Filter & Chr$(i) frm![FilterText] = StrConv(txt2Filter, vbProperCase) GoSub SetFilter End Select txtKeyUp_Exit: Exit Sub SetFilter: If Len(Nz(txt2Filter, "")) = 0 Then With frm .cboCust.RowSource = SQL .cboCust.Requery .cboCust.SetFocus .cboCust.Dropdown End With Else 'set filter and enable SQL = SQL1 & SQL2 & txt2Filter & "*'));" With frm .cboCust.RowSource = SQL .cboCust.Requery .cboCust.SetFocus .cboCust.Dropdown End With End If Return txtKeyUp_Err: MsgBox Err.Description, , "txtKeyUp()" Resume txtKeyUp_Exit End Sub Private Sub cmd_Click() DoCmd.Close acForm, frm.Name End Sub
In the earlier method, we used the Form Filter method to filter the Form Source Records based on the Filter Criteria characters entered into a TextBox.
The Combobox method builds an SQL Dynamically using the Filter Text entered into a TextBox. The SQL is used as a Row Source of the ComboBox and refreshes the Combobox contents with the changed Criteria.
Download Demo Database
- Reusing Form Module VBA Code for New Projects.
- Streamlining Form Module Code - Part Two.
- Streamlining Form Module Code - Part Three
- Streamlining Form Module Code - Part Four
- Streamlining Form Module Code - Part Five
- Streamlining Form Module Code - Part Six
- Streamlining Form Module Code - Part Seven
- Streamlining Form Module Code - Part Eight
- Streamlining Form Module Code - Part Nine
- Streamlining Form Module Code - Part Ten
- Streamlining Form Module Code - Part Elevan
- Streamlining Report Module Code in Class Module
- Streamlining Module Code Report Line Hiding-13.
- Streamlining Form Module Code Part-14.
- Streamlining Custom Made Form Wizard-15.
- Streamlining VBA Custom Made Report Wizard-16.
- Streamlining VBA External Files List in Hyperlinks-17
- Streamlining Events VBA 3D Text Wizard-18
- Streamlining Events VBA RGB Color Wizard-19
- Streamlining Events Numbers to Words-20
- Access Users Group(Europe) Presentation-21
- The Event Firing Mechanism of MS Access-22
- One TextBox and Three Wrapper Class Instances-23
- Streamlining Code Synchronized Floating Popup Form-24
- Streamlining Code Compacting/Repair Database-25
- Streamlining Code Remainder Popup Form-26
- Streamlining Code Editing Data in Zoom-in Control-27
- Streamlining Code Filter By Character and Sort-28
- Table Query Records in Collection Object-29
- Class for All Data Entry Editing Forms-30
- Wrapper Class Module Creation Wizard-31
- wrapper-class-template-wizard-v2
No comments:
Post a Comment
Comments subject to moderation before publishing.