问题
I am writing a program in Excel VBA that will basically start with one textbox and one command button, and the command button will create a new textbox and command button underneath it, and that command button will in turn create a new textbox and command button, and so on. Hope you followed that mess.
I can create the initial button no problem (it has to be dynamically created so it has the opportunity to be deleted later). My problem is then with creating the click()
event handler. I need all the click()
events to do the same thing, but name the new Objects relative to its own name. This is all blowing my mind, I would really appreciate a little help.
Feel free to ask for specific information, but I haven't really been able to wrap my head around the topic well enough to write some test code yet.
回答1:
Create a custom class module called CEventClass (Insert - Class Module, F4 to change the name). Type this code into the class module
'These are declared WithEvents so the events are
'exposed to us
Public WithEvents cmdEvent As MSForms.CommandButton
Public WithEvents tbxEvent As MSForms.TextBox
'This will fire for any control
'assigned to cmdEvent
Private Sub cmdEvent_Click()
MsgBox cmdEvent.Caption
End Sub
'This will fire for any control
'assigned to tbxEvent
Private Sub tbxEvent_Change()
If Len(tbxEvent.Text) < 6 Then
tbxEvent.BackColor = vbYellow
Else
tbxEvent.BackColor = vbWhite
End If
End Sub
Now create a Userform with no controls on it. Put this code in the form's code module
'These will keep the class instances in
'scope for as long as the form is loaded
Private mEventButtons As Collection
Private mEventTexts As Collection
Private Sub UserForm_Initialize()
Dim cmd As MSForms.CommandButton
Dim txt As MSForms.TextBox
Dim clsEventClass As CEventClass
Set mEventButtons = New Collection
Set mEventTexts = New Collection
'Create two commandbuttons
Set cmd = Me.Controls.Add("Forms.CommandButton.1", "FirstName")
cmd.Top = 10
cmd.Left = 10
cmd.Caption = "First"
'Create a new instance of CEventClass and
'assign the button to cmdEvent
Set clsEventClass = New CEventClass
Set clsEventClass.cmdEvent = cmd
mEventButtons.Add clsEventClass
Set cmd = Me.Controls.Add("Forms.CommandButton.1", "SecondName")
cmd.Top = 50
cmd.Left = 10
cmd.Caption = "Second"
Set clsEventClass = New CEventClass
Set clsEventClass.cmdEvent = cmd
mEventButtons.Add clsEventClass
'Create two textboxes and assign them to new instances
'of the class
Set txt = Me.Controls.Add("Forms.TextBox.1", "ThirdName")
txt.Top = 10
txt.Left = 150
Set clsEventClass = New CEventClass
Set clsEventClass.tbxEvent = txt
mEventTexts.Add clsEventClass
Set txt = Me.Controls.Add("Forms.TextBox.1", "FourthName")
txt.Top = 50
txt.Left = 150
Set clsEventClass = New CEventClass
Set clsEventClass.tbxEvent = txt
mEventTexts.Add clsEventClass
End Sub
Now when you run the form, those two events will fire if you click/change the control.
You may note that there is no AfterUpdate event for the textbox. That event is not actually a textbox event, but an event of the control container for the textbox, so you can't expose it this way. That's one reason I prefer to create all the controls at design time and hide or unhide them as needed. I still might use WithEvents for some controls just so I don't have to repeat code so much. But for things like TextBox_AfterUpdate, I just create all the event procedures at design time.
Update:
If you want the event to create new buttons, you have to do a couple more things. First, you have to expose the collection outside of the userform. You add this to your Userform module
Public Property Get EventButtons() As Collection
Set EventButtons = mEventButtons
End Property
Then you change your commandbutton event code to create a new button
Private Sub cmdEvent_Click()
Dim cmd As MSForms.CommandButton
Dim clsEventClass As CEventClass
Set cmd = cmdEvent.Parent.Controls.Add("Forms.CommandButton.1", cmdEvent.Caption & "1")
cmd.Top = cmdEvent.Top + 40
cmd.Left = cmdEvent.Left
cmd.Caption = cmdEvent.Caption & "1"
Set clsEventClass = New CEventClass
Set clsEventClass.cmdEvent = cmd
cmdEvent.Parent.EventButtons.Add clsEventClass
End Sub
This creates a new button 40 points below whichever was clicked. You don't say what your logic is for naming or positioning, so I assume you can work that out. Use cmdEvent.Parent to get a reference to the Userform.
来源:https://stackoverflow.com/questions/24558214/actions-for-multiple-similar-dynamically-created-command-buttons