jwcolby54
Member
- Local time
- Yesterday, 19:07
- Joined
- May 19, 2025
- Messages
- 51
I read with interest a thread which described the machinations that folks went through to do something that is simple with RaiseEvent.
The OP wanted a form with a ton of buttons on it. She created a clsBtn (good job) which the form used to encapsulate each buttons. As many buttons as the OP wanted. Saved into a collection. Good Job.
BUT... she wanted the button click to do something back on the form. Hmmmm... without a variable dimmed Withevents, there is no direct way to do this. But it can be done with a very useful singleton message class. Get a pointer to this clsMsgPD and store it in the class header Withevents... and the magic begins.
This is mostly just aircode, written in the middle of the night as my daughter slept. But I will work with anyone who wishes to actually try this.
First the clsCmd. Store this in a class named clsCmd. I acttually wrote this class and it compiles.
Option Compare Database
Option Explicit
Private WithEvents mCmd As CommandButton 'Holds a pointer to the command button
Private Sub Class_Terminate()
Set mCmd = Nothing 'Clean up behind our Self
End Sub
Public Function fInit(lCmd As CommandButton) 'Get a pointer to a command button
Set lCmd = mCmd 'and store it in the header of this class
End Function
'
'Now sink the click event
'
Private Sub mCmd_Click()
'
'call the message class to send a message
'Say who we are in the first parameter
'And pass a pointer to the actual command button in the last parameter
'
clsMsgPD.Send mCmd.Name, "", "", mCmd
End Sub
Let's create a simple clsMsgPD (PreDeclared). It doesn't do much except raise an event to send a message. Suppose we create a singleton clsMsgPD.
I have used clsMsgPD for years. It functions as described.
Place the following in a new class and save it as clsMsgPD. Export it to a text file.
Change 'Attribute VB_PredeclaredId = True
Import back into the database.
Option Compare Database
Option Explicit
'
'clsMsgPD is a "PreDeclared" class which does not have to be instantiated.
'This has been done by exporting clsMsg, editing it in an editor setting
'and pulling it back in.
'Attribute VB_PredeclaredId = True
'
'And then importing the class back into Access.
'I then renamed clsMsg1 to clsMsgPD.
'
Public Event Message(varFrom As Variant, varTo As Variant, _
varSubj As Variant, varMsg As Variant)
Public Event MessageSimple(varMsg As Variant)
Function Send(varFrom As Variant, varTo As Variant, _
varSubj As Variant, varMsg As Variant)
RaiseEvent Message(varFrom, varTo, varSubj, varMsg)
' Debug.Print "From: " & varFrom & vbCrLf & "To: " & varTo & vbCrLf & "Subj: " & varSubj & vbCrLf & "Msg: " & varMsg
End Function
Function SendSimple(varMsg As Variant)
RaiseEvent MessageSimple(varMsg)
' Debug.Print varMsg
End Function
Now anybody from anywhere can raise a message. The key here is that RaiseEvent can pass variants. And variants can contain anything including pointers to objects such as a button. So the varMsg parameter can be the actual button if so desired. OR it can simply be the name of the button. OR it can be the back color of the button. You get the idea.
In a new form place a text box on the form called txtSomeMsg. And BUNCH of buttons named Cmd1, Cmd2, Cmd3 etc.
Now in the header of the form with all these buttons on it:
'Get an instance of that singleton or "predeclared" class
Dim Withevents mClsMsgPD as clsMsgPD.
'And a collection to hold all the clsMsg instances
Dim mcolClsButtons as collection
Private Sub Form_Open(Cancel As Integer)
Set mcolClsButtons = new Collection
Set mClsMsgPD = new clsMsgPD
lclsCmdFactory Cmd1
lclsCmdFactory Cmd2
lclsCmdFactory Cmd3
'... as many times as you want
End Sub
'
'NEVER forget to clean up behind ourselves
'
Private Sub Form_Close()
Set mClsMsgPD = Nothing
Set mcolClsButtons = Nothing
End Sub
'
'this is a factory for creating instances of clsCmd and storing them in the collection
'
function clsCmdFactory(lCmd As CommandButton )
dim lclsCmd as clsCmd
Set lclsCmd = new clsCmd
lclsCmd.fInit(lCmd)
'
'And store the new clsCmd instance in the collection
'
mcolClsButtons.add lclsCmd
end function
'
'This is the event sink for the message class which the form is listening to
'In here we will expect the clsButton to send itself (the actual button object)
'as the varMsg parameter.
'
Private Sub mClsMsgPD_Message(varFrom As Variant, varTo As Variant, varSubj As Variant, varMsg As Variant)
dim lBtn as CommandButton
'varMsg will be a pointer to a button which is sending a message
Set lBtn = varMsg 'This code coerces the variant message into a command button
txtSomeMsg = lBtn.Name & " is calling back to the form which contains me."
End Sub
The OP wanted a form with a ton of buttons on it. She created a clsBtn (good job) which the form used to encapsulate each buttons. As many buttons as the OP wanted. Saved into a collection. Good Job.
BUT... she wanted the button click to do something back on the form. Hmmmm... without a variable dimmed Withevents, there is no direct way to do this. But it can be done with a very useful singleton message class. Get a pointer to this clsMsgPD and store it in the class header Withevents... and the magic begins.
This is mostly just aircode, written in the middle of the night as my daughter slept. But I will work with anyone who wishes to actually try this.
First the clsCmd. Store this in a class named clsCmd. I acttually wrote this class and it compiles.
Option Compare Database
Option Explicit
Private WithEvents mCmd As CommandButton 'Holds a pointer to the command button
Private Sub Class_Terminate()
Set mCmd = Nothing 'Clean up behind our Self
End Sub
Public Function fInit(lCmd As CommandButton) 'Get a pointer to a command button
Set lCmd = mCmd 'and store it in the header of this class
End Function
'
'Now sink the click event
'
Private Sub mCmd_Click()
'
'call the message class to send a message
'Say who we are in the first parameter
'And pass a pointer to the actual command button in the last parameter
'
clsMsgPD.Send mCmd.Name, "", "", mCmd
End Sub
Let's create a simple clsMsgPD (PreDeclared). It doesn't do much except raise an event to send a message. Suppose we create a singleton clsMsgPD.
I have used clsMsgPD for years. It functions as described.
Place the following in a new class and save it as clsMsgPD. Export it to a text file.
Change 'Attribute VB_PredeclaredId = True
Import back into the database.
Option Compare Database
Option Explicit
'
'clsMsgPD is a "PreDeclared" class which does not have to be instantiated.
'This has been done by exporting clsMsg, editing it in an editor setting
'and pulling it back in.
'Attribute VB_PredeclaredId = True
'
'And then importing the class back into Access.
'I then renamed clsMsg1 to clsMsgPD.
'
Public Event Message(varFrom As Variant, varTo As Variant, _
varSubj As Variant, varMsg As Variant)
Public Event MessageSimple(varMsg As Variant)
Function Send(varFrom As Variant, varTo As Variant, _
varSubj As Variant, varMsg As Variant)
RaiseEvent Message(varFrom, varTo, varSubj, varMsg)
' Debug.Print "From: " & varFrom & vbCrLf & "To: " & varTo & vbCrLf & "Subj: " & varSubj & vbCrLf & "Msg: " & varMsg
End Function
Function SendSimple(varMsg As Variant)
RaiseEvent MessageSimple(varMsg)
' Debug.Print varMsg
End Function
Now anybody from anywhere can raise a message. The key here is that RaiseEvent can pass variants. And variants can contain anything including pointers to objects such as a button. So the varMsg parameter can be the actual button if so desired. OR it can simply be the name of the button. OR it can be the back color of the button. You get the idea.
In a new form place a text box on the form called txtSomeMsg. And BUNCH of buttons named Cmd1, Cmd2, Cmd3 etc.
Now in the header of the form with all these buttons on it:
'Get an instance of that singleton or "predeclared" class
Dim Withevents mClsMsgPD as clsMsgPD.
'And a collection to hold all the clsMsg instances
Dim mcolClsButtons as collection
Private Sub Form_Open(Cancel As Integer)
Set mcolClsButtons = new Collection
Set mClsMsgPD = new clsMsgPD
lclsCmdFactory Cmd1
lclsCmdFactory Cmd2
lclsCmdFactory Cmd3
'... as many times as you want
End Sub
'
'NEVER forget to clean up behind ourselves
'
Private Sub Form_Close()
Set mClsMsgPD = Nothing
Set mcolClsButtons = Nothing
End Sub
'
'this is a factory for creating instances of clsCmd and storing them in the collection
'
function clsCmdFactory(lCmd As CommandButton )
dim lclsCmd as clsCmd
Set lclsCmd = new clsCmd
lclsCmd.fInit(lCmd)
'
'And store the new clsCmd instance in the collection
'
mcolClsButtons.add lclsCmd
end function
'
'This is the event sink for the message class which the form is listening to
'In here we will expect the clsButton to send itself (the actual button object)
'as the varMsg parameter.
'
Private Sub mClsMsgPD_Message(varFrom As Variant, varTo As Variant, varSubj As Variant, varMsg As Variant)
dim lBtn as CommandButton
'varMsg will be a pointer to a button which is sending a message
Set lBtn = varMsg 'This code coerces the variant message into a command button
txtSomeMsg = lBtn.Name & " is calling back to the form which contains me."
End Sub