Excel VBA如何链接类和控件?
我将Excel 2003与VBA一起使用,在工作表上动态创建复选框控件,并希望将VBA控件链接到类,以便当用户单击复选框时触发事件,以便我可以执行某些操作 从我所读到的内容来看,创建用户类似乎是一个解决方案,但尝试了这个方法后,我无法让它工作 我的用户类如下所示:Excel VBA如何链接类和控件?,excel,vba,Excel,Vba,我将Excel 2003与VBA一起使用,在工作表上动态创建复选框控件,并希望将VBA控件链接到类,以便当用户单击复选框时触发事件,以便我可以执行某些操作 从我所读到的内容来看,创建用户类似乎是一个解决方案,但尝试了这个方法后,我无法让它工作 我的用户类如下所示: Option Explicit Public WithEvents cbBox As MSForms.checkbox Private Sub cbBox_Change() MsgBox "
Option Explicit
Public WithEvents cbBox As MSForms.checkbox
Private Sub cbBox_Change()
MsgBox "_CHANGE"
End Sub
Private Sub cbBox_Click()
MsgBox "_CLICK"
End Sub
创建复选框的我的代码:
For Each varExisting In objColumns
'Insert the field name
objColumnHeadings.Cells(lngRow, 1).Value = varExisting
'Insert a checkbox to allow selection of the column
Set objCell = objColumnHeadings.Cells(lngRow, 2)
Dim objCBclass As clsCheckbox
Set objCBclass = New clsCheckbox
Set objCBclass.cbBox = ActiveSheet.OLEObjects.Add( _
ClassType:="Forms.CheckBox.1" _
, Left:=300 _
, Top:=(objCell.Top + 2) _
, Height:=10 _
, Width:=9.6).Object
objCBclass.cbBox.Name = "chkbx" & lngRow
objCBclass.cbBox.Caption = ""
objCBclass.cbBox.BackColor = &H808080
objCBclass.cbBox.BackStyle = 0
objCBclass.cbBox.ForeColor = &H808080
objCheckboxes.Add objCBclass
lngRow = lngRow + 1
Next
这些复选框在工作表中可见,但当我单击它们时,没有显示任何消息框,因此指向该类的链接似乎不起作用
为什么?
编辑…如果在添加复选框后,我进入VB IDE并从控件列表中选择一个已创建的复选框,然后从过程下拉列表中选择“单击”,它将插入回拨代码,如果我在其中添加一个消息框,当我单击同一复选框时,该代码将起作用…那么我如何在代码中实现这一点?我尝试录制宏来执行此操作,但未录制任何内容。您当前正在使用ActiveX控件。然而,ActiveX控件受特定命名约定的约束。例如:如果在工作表上插入ActiveX按钮并将其命名为
btnMyButton
,则必须将子按钮命名为btnMyButton\u单击
。这同样适用于复选框。如果插入名为CheckBox2
的新复选框,则子项的名称必须为CheckBox2\u单击。简而言之,名称为cbBox\u Change
的子项不能与任何ActiveX复选框关联
因此,您真正需要(使用ActiveX控件)的是一种更改工作表上VBA代码的方法。但到目前为止,我从未遇到过任何这样的代码(在工作表上更改VBA代码的VBA代码)
如果你愿意改用,一条更容易的路线会是
下面的子项将创建一个(表单控件)复选框并tmpSO
。subtmpSO
(与ActiveX控件的sub不同)不需要驻留在工作表上,但可以位于任何模块中
Sub Insert_CheckBox()
Dim chk As CheckBox
Set chk = ActiveSheet.CheckBoxes.Add(390.75, 216, 72, 72)
chk.OnAction = "tmpSO"
End Sub
由于控件中的正在调用subtmpSO
,因此您可以在该sub中使用Application.Caller
,从而知道哪个复选框调用了此sub
Sub tmpSO()
Debug.Print Application.Caller
End Sub
这将返回复选框的名称。因此,您可以将此子项用于所有复选框,根据它们的名称动态处理它们(可能使用案例选择
)
下面是tmpSO
的另一个示例:
Sub tmpSO()
With ThisWorkbook.Worksheets(1).CheckBoxes(Application.Caller)
MsgBox "The checkbox " & Application.Caller & Chr(10) & _
"is currently " & IIf(.Value = 1, "", "not") & " checked."
End With
End Sub
由S.Platten编辑,跳到底部了解这是如何帮助我解决问题的
由于某些奇怪的原因,VBA没有在添加事件的同一执行周期中连接Sheet ActiveX控件的事件。因此,我们需要走出添加控件的循环,然后在下一个循环中调用事件添加过程<代码>应用程序.OnTime
在此提供帮助
这似乎有点过分,但效果不错:)
编辑继续
类(clsCheckbox):
模块1
Public objCheckboxes As Collection
Public tmrTimer
Public Sub addEvents()
Dim objCheckbox As clsCheckbox
Dim objMSCheckbox As Object
Dim objControl As Object
Set objCheckboxes = New Collection
For Each objControl In Sheet1.OLEObjects
If objControl.OLEType = 2 _
And objControl.progID = "Forms.CheckBox.1" Then
Set objMSCheckbox = objControl.Object
Set objCheckbox = New clsCheckbox
Set objCheckbox.cbBox = objMSCheckbox
objCheckboxes.Add objCheckbox
End If
Next
Call stopTimer
End Sub
Public Sub startTimer()
tmrTimer = Now + TimeSerial(0, 0, 1)
Application.OnTime EarliestTime:=tmrTimer _
, Procedure:="addEvents" _
, Schedule:=True
End Sub
Public Sub stopTimer()
On Error Resume Next
Application.OnTime EarliestTime:=tmrTimer _
, Procedure:="addEvents" _
, Schedule:=False
End Sub
工作表中添加控件的代码:
Dim objControl As MSForms.checkbox
For Each varExisting In objColumns
'Insert the field name
objColumnHeadings.Cells(lngRow, 1).Value = varExisting
'Insert a checkbox to allow selection of the column
Set objCell = objColumnHeadings.Cells(lngRow, 2)
Set objControl = ActiveSheet.OLEObjects.Add( _
ClassType:="Forms.CheckBox.1" _
, Left:=300 _
, Top:=(objCell.Top + 2) _
, Height:=10 _
, Width:=9.6).Object
objControl.Name = "chkbx" & lngRow
objControl.Caption = ""
objControl.BackColor = &H808080
objControl.BackStyle = 0
objControl.ForeColor = &H808080
lngRow = lngRow + 1
Next
这不是整个项目,但足以演示工作原理。谢谢,有些帖子用同样的方式创建的按钮进行了关闭,但是我看不出这些如何与用户类一起工作,而且我自己也尝试过,我无法让它触发事件。您可以使用VBA扩展性库使用VBA代码来编写工作表代码。但是,您必须在安全设置中信任对VBA项目的访问。在Chip Pearson的@Splaten上给出了一个具体的例子,并进行了更一般性的讨论。我不确定您的问题是什么。只需复制subInsert_复选框和subtmpSO
。然后运行插入\u复选框
。之后,您将有一个复选框,其中“ever sheet”处于活动状态,如果您单击该复选框,您将得到一个debug.print
或MsgBox
(取决于您复制的哪个tmpSO sub)。就这样。完成。无类模块,无需编码的其他事件。就这么简单,问题是所有东西都是用代码创建的,运行时没有任何东西放在工作表上,因此我需要能够在运行时创建事件处理程序。到目前为止什么都不起作用。上面的subInsert_CheckBox
没有创建复选框?objcheckbox声明在哪里?objcheckbox只是一个集合。我意识到,但我偶尔会犯错误,在填充它的sub中声明它,而不是作为全局…谢谢,今晚我将实现这一点并发回。我在这一行得到一个类型不匹配的结果:Set ctrlChkBox=x。Object我已经检查了代码,并且我确定我已经正确地复制了它。嗯,,,,,不确定为什么会发生在你身上。刚刚测试了代码,它就成功了。您正在使用与MSForms相同的声明Dim ctrlChkBox。addControls和addEvents中的复选框
?只需将整个代码集复制到新的工作手册中,然后查看它是否有效。希望您在复制粘贴时错过了一些内容。:)我刚才做了这件事,它立即出现错误:Dim ctrlChkBox作为MSForms.Checkbox带有“用户定义类型未定义”
Option Explicit
Public WithEvents cbBox As MSForms.checkbox
Private Sub cbBox_Click()
MsgBox "_CLICK"
End Sub
Public objCheckboxes As Collection
Public tmrTimer
Public Sub addEvents()
Dim objCheckbox As clsCheckbox
Dim objMSCheckbox As Object
Dim objControl As Object
Set objCheckboxes = New Collection
For Each objControl In Sheet1.OLEObjects
If objControl.OLEType = 2 _
And objControl.progID = "Forms.CheckBox.1" Then
Set objMSCheckbox = objControl.Object
Set objCheckbox = New clsCheckbox
Set objCheckbox.cbBox = objMSCheckbox
objCheckboxes.Add objCheckbox
End If
Next
Call stopTimer
End Sub
Public Sub startTimer()
tmrTimer = Now + TimeSerial(0, 0, 1)
Application.OnTime EarliestTime:=tmrTimer _
, Procedure:="addEvents" _
, Schedule:=True
End Sub
Public Sub stopTimer()
On Error Resume Next
Application.OnTime EarliestTime:=tmrTimer _
, Procedure:="addEvents" _
, Schedule:=False
End Sub
Dim objControl As MSForms.checkbox
For Each varExisting In objColumns
'Insert the field name
objColumnHeadings.Cells(lngRow, 1).Value = varExisting
'Insert a checkbox to allow selection of the column
Set objCell = objColumnHeadings.Cells(lngRow, 2)
Set objControl = ActiveSheet.OLEObjects.Add( _
ClassType:="Forms.CheckBox.1" _
, Left:=300 _
, Top:=(objCell.Top + 2) _
, Height:=10 _
, Width:=9.6).Object
objControl.Name = "chkbx" & lngRow
objControl.Caption = ""
objControl.BackColor = &H808080
objControl.BackStyle = 0
objControl.ForeColor = &H808080
lngRow = lngRow + 1
Next