MajP
You've got your good things, and you've got mine.
- Local time
- Today, 05:09
- Joined
- May 21, 2018
- Messages
- 9,538
This is in response to question posed by @Gasman here
@Gasman,
Let me explain how I do it, you can take it or leave it but it works.
Almost always when I build a custom collection that wraps control events and I am working with more than one control I build a matching custom collection class
This is makes adding creating groups of controls so much easier
So I make a class
clsAlphaCmds to hold groups of clsAlphaCmd
This is a cut and paste exercise done the same way every time.
In the Collection Class I add one method where each control that raises an event calls it.
Now I create, add, and remove clsAlphaCmd only through the class. See the Collection class add method.
In clsAlphaCmd I do one more thing. I tell the clsAlphaCmd who the parent collection is.
Now you are done.
In the form you add only the Custom Collection with Events.
The individual clsAlphaCommand call a procedure in the collection class that raises an event.
Load the Collection in the Form
Then Listen to the Collection Class to Raise an Event
To summarize this technique
To Summarize
You custom class is usually some kind of control wrapper where you add a control to your custom class and trap its events. If VBA had inheritance this would all be much easier to do. Instead of inheritance we have to use the principle of Composition. The custom class is Composed of the control as a property of the class. Along with all the other properties we want to add.
1. In your custom class you need to add a property to maintain a reference to the related parent Collection Class. I called it Parent Collection.
2. Create a custom collection class. This wraps all the normal collection methods such as Add, Item, Remove, Count etc. Cut and Paste replace names.
2. In the collection class you add a method/s that the individual items (custom class objects) call when they trap a control event. This method then raises a custom event in the collection class. Now in your form listen to the collection class that is reporting events from the individual items in the collection.
3. Trap the collection class event in your main form.
This is kind of a chain. The custom class traps a control event. The custom class calls a method in the parent collection class which in turn raises a custom event. Your form listens to the the Collection Class custom event.
5. When creating custom class items you do this through the collection class add method. This passes a reference for the Collection Class to each custom class object. You never really work directly with the custom class. You do everything including trapping events through the collection class.
There is some similar discussion here, but I demo a simple listener instead of a custom collection class. But for me a collection class takes 5 minutes and it is just easier to add one even if it can be done without it.
Hopefully this provides sufficient explanation while under 5 pages, because that is how I roll.
The message class - RAISING events
@jwcolby54 Can we take a break from the book for a short while please? I am trying to implement what I have read into the attached DB, which is from another member here. I believe I fixed their issue with just a common routine, but can see the potential for a class for the certain command...
www.access-programmers.co.uk
@Gasman,
Let me explain how I do it, you can take it or leave it but it works.
Almost always when I build a custom collection that wraps control events and I am working with more than one control I build a matching custom collection class
Advanced Class Concepts
Advanced Class Concepts I have posted several threads on using custom classes to extend the capabilities of controls and make pseudo "user controls". https://www.access-programmers.co.uk/forums/threads/developing-custom-classes-to-simulate-user-controls.309080/ This thread has additional concepts.
www.access-programmers.co.uk
This is makes adding creating groups of controls so much easier
So I make a class
clsAlphaCmds to hold groups of clsAlphaCmd
Code:
Option Compare Database
Option Explicit
Private m_AlphaCmds As New Collection
Public Event AlphaCommandClicked(ClickedCommand As CommandButton)
Public Function Add(TheCommandButton As Access.CommandButton, iAlpha As Integer) As ClsAlphaCmd
'create a new AlphaCmd and add to collection
Dim NewAlphaCmd As New ClsAlphaCmd
NewAlphaCmd.fInit TheCommandButton, iAlpha, Me
m_AlphaCmds.Add NewAlphaCmd, CStr(iAlpha)
Set Add = NewAlphaCmd
End Function
Public Sub Add_AlphaCmd(ByVal TheAlphaCmd As ClsAlphaCmd)
'I also add a second Add to allow you to build the object and then assign it
m_AlphaCmds.Add TheAlphaCmd, TheAlphaCmd.Name
End Sub
Public Property Get Count() As Long
Count = m_AlphaCmds.Count
End Property
Public Property Get NewEnum() As IUnknown
'Attribute NewEnum.VB_UserMemId = -4
'Attribute NewEnum.VB_MemberFlags = "40"
'This is allows you to iterate the collection "For Each AlphaCmd in AlphaCmds"
Set NewEnum = m_AlphaCmds.[_NewEnum]
End Property
Public Property Get Item(Name_Or_Index As Variant) As ClsAlphaCmd
'Attribute Item.VB_UserMemId = 0
'Export the class and uncomment the below in a text editer to allow this to be the default property
'Then reimport
Set Item = m_AlphaCmds.Item(Name_Or_Index)
End Property
Sub Remove(Name_Or_Index As Variant)
'remove this person from collection
'The name is the key of the collection
m_AlphaCmds.Remove Name_Or_Index
End Sub
Public Property Get ToString() As String
Dim strOut As String
Dim i As Integer
For i = 1 To Me.Count
strOut = strOut & Me.Item(i).ToString & vbCrLf
Next i
ToString = strOut
End Property
'----------------------------------------------- All Classes Have 2 Events Initialize and Terminate --------
Private Sub Class_Initialize()
'Happens when the class is instantiated not related to the fake Initialize method
'Do things here that you want to run on opening
Set m_AlphaCmds = New Collection
End Sub
Private Sub Class_Terminate()
'Should set the object class properties to nothing
Set m_AlphaCmds = Nothing
End Sub
'****************************************************************************************************************************************************************
'----------------------------------------------------------------------------------- The Clicked AlphaCommad calls this Method -------------------------------------------------------------
'*****************************************************************************************************************************************************************
'
Public Sub RaiseClickEvent(TheCommand As CommandButton)
RaiseEvent AlphaCommandClicked(TheCommand)
'MsgBox "Raise in Collection Class"
End Sub
This is a cut and paste exercise done the same way every time.
In the Collection Class I add one method where each control that raises an event calls it.
Now I create, add, and remove clsAlphaCmd only through the class. See the Collection class add method.
In clsAlphaCmd I do one more thing. I tell the clsAlphaCmd who the parent collection is.
Code:
Private WithEvents mCmd As CommandButton
Private ParentCollection As ClsAlphaCmds
Private Const mcstrEvProc As String = "[Event Procedure]"
Private Const cstrAlphabet As String = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Public Function fInit(lCmd As CommandButton, iAlpha As Integer, TheParentCollection As ClsAlphaCmds)
Set mCmd = lCmd
mCmd.Caption = Mid(cstrAlphabet, iAlpha, 1)
mCmd.OnClick = mcstrEvProc
Set ParentCollection = TheParentCollection
End Function
Private Sub Class_Terminate()
Set mCmd = Nothing
End Sub
'****************************************************************************************************************************************************************
'----------------------------------------------------------------------------------- call the parent collection to raise an event -------------------------------------------------------------
'*****************************************************************************************************************************************************************
Private Sub mCmd_Click()
ParentCollection.RaiseClickEvent mCmd
End Sub
Now you are done.
In the form you add only the Custom Collection with Events.
The individual clsAlphaCommand call a procedure in the collection class that raises an event.
Load the Collection in the Form
Code:
Private Sub Form_Load()
Call SetAlphaButtons ' Initialise the command buttons via a class
End Sub
Private Sub SetAlphaButtons()
' Use clsCommand for the buttons for alphabet
Dim i As Integer
Set AlphaCommands = New ClsAlphaCmds
For i = 1 To 27
Debug.Print Me.Controls("AlphaTab" & i).Caption & " - " & Me.Controls("AlphaTab" & i).Name
' Set Me.Controls("AlphaTab" & i) = ClsAlphaCmd()
AlphaCommands.Add Me.Controls("AlphaTab" & i), i
Next
End Sub
Then Listen to the Collection Class to Raise an Event
Code:
'****************************************************************************************************************************************************************
'----------------------------------------------------------------------------------- Locate Record -------------------------------------------------------------
'*****************************************************************************************************************************************************************
Private Sub AlphaCommands_AlphaCommandClicked(ClickedCommand As CommandButton)
LocateRecord ClickedCommand
End Sub
Private Sub LocateRecord(ClickedCommand As CommandButton)
Dim i As Integer
MsgBox "Trap in Form Command caption " & ClickedCommand.Caption
DoCmd.RunCommand acCmdSaveRecord
Me.Recordset.FindFirst "[AAC] = '" & strCaption & "'"
Me.NavMenu = Me.NavMenu.ItemData(AIN) 'RecordsetClone![AIN]
'Debug.Print strCaption & " - " & Me.NavMenu.ItemData(AIN) & " - " & AIN
End Sub
To summarize this technique
To Summarize
You custom class is usually some kind of control wrapper where you add a control to your custom class and trap its events. If VBA had inheritance this would all be much easier to do. Instead of inheritance we have to use the principle of Composition. The custom class is Composed of the control as a property of the class. Along with all the other properties we want to add.
1. In your custom class you need to add a property to maintain a reference to the related parent Collection Class. I called it Parent Collection.
2. Create a custom collection class. This wraps all the normal collection methods such as Add, Item, Remove, Count etc. Cut and Paste replace names.
2. In the collection class you add a method/s that the individual items (custom class objects) call when they trap a control event. This method then raises a custom event in the collection class. Now in your form listen to the collection class that is reporting events from the individual items in the collection.
3. Trap the collection class event in your main form.
This is kind of a chain. The custom class traps a control event. The custom class calls a method in the parent collection class which in turn raises a custom event. Your form listens to the the Collection Class custom event.
5. When creating custom class items you do this through the collection class add method. This passes a reference for the Collection Class to each custom class object. You never really work directly with the custom class. You do everything including trapping events through the collection class.
There is some similar discussion here, but I demo a simple listener instead of a custom collection class. But for me a collection class takes 5 minutes and it is just easier to add one even if it can be done without it.
Need some advice on a simple Class
Pretty new to classes. Here's a simple class I have. Private WithEvents m_Label As Label Private LabelCollection As Collection '************************************************************************' Public Sub init(frm As Access.Form) Dim Ctrl As Control Dim srtCtrl As clsMyClass...
www.access-programmers.co.uk
Hopefully this provides sufficient explanation while under 5 pages, because that is how I roll.