VB动态加载ActiveX控件并响应事件
熟悉VB的朋友对使⽤ActiveX控件⼀定不会陌⽣,众多控件极⼤地⽅便了编程,但唯⼀的缺陷是不能动态加载控件,必须在设计时通过引⽤,将控件放置在窗体上。VB6.0已能够解决该问题,只是帮助中没有明确说明,并且没有描述到⼀些关键功能,由于以前的版本中可以动态创建进程外服务:如果对象是外部可创建的,可在 Set 语句中⽤ New 关键字、CreateObject 或 GetObject 从部件外⾯将对象引⽤赋予变量。如果对象是从属对象,则需使⽤⾼层对象的⽅法,在 Set 语句中指定⼀个对象引⽤:
Dim xlApp1 As Excel.Application
Set xlApp1 = New Excel.Application
或
Dim xlApp As Object '定义存放引⽤对象的变量。
Set xlApp = CreateObject("excel.application")
xlApp.Visible = True
-
--- 这些语法很容易造成误导,以为动态加载ActiveX控件也是此⽅法,可能有朋友也象我⼀样利⽤CreateObject尝试了⽆数次,却⽆功⽽返,不知微软公司是出于何种考虑,动态加载ActiveX控件是扩展控件集合的⽅式实现,通过实际摸索,终于就如何实现动态ActiveX控件出了⼀条切实可⾏的⽅法,下⾯以⼀个具体的实例来详细说明。
---- ⼀、ActiveX控件
---- ActiveX 控件是 Visual Basic ⼯具箱的扩充部分。使⽤ ActiveX 控件的⽅法与使⽤其它标准内装的控件,如 CheckBox 控件,完全⼀样。在程序中加⼊ ActiveX 控件后,它将成为开发和运⾏环境的⼀部分,并为应⽤程序提供新的功能。
---- ActiveX 部件通过客户端/服务器关系与应⽤程序— 及与部件相互之间— 交互作⽤。客户端是使⽤部件功能的应⽤程序代码或部件。服务器是部件及其关联的对象。例如,假设应⽤程序使⽤ ActiveX 控件来提供⼀个标准的雇员窗体,供公司的多种应⽤程序使⽤。提供雇员窗体的 ActiveX 控件就是服务器,使⽤这个控件的应⽤程序就是服务器的客户端。
---- ⼆、加载⽅法
---- VB6.0中对Controls 集合进⾏了扩展,以前版本中Controls 集合在窗体上列举出已加载的控件,这
在迭代过程中是很有⽤的。Controls 集合标识⼀个叫做 Controls 的内在窗体级变量。如果忽略可选的 object 所在处的整数,则关键字 Controls 必须包括在内。我们通常在窗⼝中使⽤如下代码:
Text1.Text="Hello, world"
其实也可以使⽤如下代码达到同⼀⽬的:
Controls(1).Text="Hello, world"
---- 在VB6.0中除了原来的Clear、Remove ⽅法外(很奇怪,为什么微软在VB5.0中只提供这两种⽅法,⽽没有提供Add⽅法,因为没有Add,这两种⽅法也就没什么⽤处),增加了Add⽅法,该⽅法就是⽤于动态加载控件的:
Controls.Add(progid as String, Name as String);
progid: ActiveX部件的ProgID,如:"VB.CheckBox";
Name:ActiveX部件加载后的名称,如: "MyCheckBox";
若要在窗体上添加⼀个名为MyButton的按钮,可以使⽤:
dim oControl as Object '窗体级变量
注意:这⾥声明为Object对象类型
Private Sub LoadControl()
Set oControl = Controls.Add
("VB.CommandButton", "MyButton")
oControl.Left = 10
oControl.Top = 10
oControl.Visible = True '使控件可见
End Sub
---- 这是VB6.0的标准语法,它在例程中也是如此演⽰的,不过该⽅法虽然现实了控件的动态加载,按钮显⽰在窗体上,可以象普通按钮⼀样按下去,但加载的控件不能预先设计响应事件代码,如:事件Sub MyButton_Click()将是⾮法的,当然,可以将要响应的事件封装在控件内部。就编程的观点来看该
⽅法没什么⼤的⽤处,开发ActiveX控件的⽬的是为了资源共享,为了被其他开发⼈员利⽤,所以要提供必要的事件接⼝,显然利⽤该⽅法不⾏,通过分析VBControls等相关对象,出VBControlExtender对象与EventInfo相结合能提供事件陷井
捕捉,VBControlExtender对象对动态添加控件特别有⽤,它提供了⼀套通⽤的属性、⽅法、事件给开发⼈员,它的⼀个突出特点是能编程设计控件的事件,熟习类编程的朋友对带事件的对象声明⼀定不会陌⽣:
---- Dim WithEvents objElemt as CElemtVBControlExtender也不例外,声明的语法⼀样,只不过它有个特殊的事件ObjectEvent(Info As EventInfo),它能捕捉到对象使⽤RaiseEvent产⽣的所有事件,EventInfo数据结构映射了事件的名称、参数个数和参数的值。VBControlExtender和 EventInfo相结合,采⽤Select Case 就可以预先将不同类对象的事件放置⼀起,各⾃独⽴运作。将上⾯的代码改写⼀下就能提供Click事件了:
---- Dim WithEvents oControl As VBControlExtender '带事件声明声明之后您就可以在代码窗⼝的左上⾓的对象下拉框中发现该对象出现了,也就是说,该对象有了事件或⽅法了,它的事件有DragDrop,DragOver ,LostFocus ,GotFocus ,ObjectEvent和Validate,其中ObjectEvent是通⽤的事件捕捉。
Private Sub LoadControl()
Set oControl = Controls.Add
("VB. CommandButton", "MyButton")
oControl.Visible = True
End Sub
Private Sub oControl_ObjectEvent(Info As EventInfo)
Select Case Info.Name
Case "Click" 'Click事件
'您可以添加处理Click事件代码
MsgBox "您按了MyButton!"
Case Else ' 其他事件
' Handle unknown events here.
End Select
End Sub
---- 当然对微软提供的标准控件能采⽤该⽅法添加,⼤家都不会怀疑,但⾃⼰开发的控件也能吗?答案是肯定的,我们可以⽤⼀个实际的例⼦进⾏说明。
---- 三、实例描述
---- 假设⼀个本地⽹络的监控系统,需要在原理图与实物⽰意图间切换,原理图包括组⽹结构、传输资源、监控主机等,⽽实物⽰意图包括路由器、设备、采集器等,当然两种图的事件要⼀致,如双击某个设备图形将显⽰给设备的实时数据等,为了简化维护,将原理图与实物⽰意图封装成ActiveX控件,由于每种图需要加载许多图形控件,消耗资源较⼤,不能同时加载,需要将其分解为两个控件,在切换时⾸先卸载⼀个控件,然后加载另⼀个控件,所以要实现动态加载ActiveX控件。
---- 原理图控件为-- ,对应⼯程为CTheory;
---- 实物图控件为--- ,对应⼯程为CFact;
---- 注意:为了简化,在设计控件时不设置许可证关键字。
---- 实物图控件上的图形对象可以被拖动,拖动后的位置信息通过事件ChangePosition来通知拥有该控件的窗体,以便下次加载能显⽰在最后位置,实物图和原理图控件都有双击事件完成的⼯作相同,其他事件此处忽略。
---- 四、具体⽰例
---- 1、准备⼯作
---- 对控件 、 进⾏注册(利⽤注册);
---- 建⽴窗体frmTest.frm ,在窗体上放置按钮cmdLoadOcx—“原理图”
---- 2、声明窗体级变量与加载函数LoadControl
Dim WithEvents oControl As VBControlExtender
'地图仿真控件对象
Dim mblnTheory As Boolean '是否显⽰原理图
Private Function LoadControl(intType As Integer)
If Not oControl Is Nothing Then
'⾸先判断对象是否存在,若存在则卸载
Controls.Remove("MapView")
'卸载控件,此操作⾮常重要
End If
If intType = 0 Then
Set oControl = Controls.Add
("CTheory. Theory", "MapView")
Else
Set oControl = Controls.Add
("CFact.Fact", "MapView")
End If
oControl.Height = 3500
oControl.Width = 6500
oControl.Top = 100
oControl.Visible = True
End Function
Private Sub Form_Load()
mblnTheory = True
End Sub
---- 3、为按钮cmdLoadOcx编写代码
Private Sub cmdLoadOCX_Click()
If mblnTheory Then
Call LoadControl(0)
mblnTheory = False
cmdLoadOCX.Caption = "实物图"
activex 控件Else
Call LoadControl(1)
mblnTheory = True
cmdLoadOCX.Caption = "原理图"
End If
End Sub
---- 4、为事件ChangePosition编写代码
Private Sub oControl_ObjectEvent
(Info As EventInfo)
Select Case Info.Name
Case "ChangePosition"
MsgBox CStr(Info.EventParamters.Item(
1).Value) + ":" + _
CStr(Info.EventParamters.Item(2).Value)
Case "DbClick"
'双击处理代码
Case Else '
End Select
End Sub
---- 注意: EventInfo的参数EventParamters集合中是以1开始的,⼀般来说,微软新的集合⼀般是以1开始的,⽽旧的是以0开始的,如RdoErrors.Item(0)。
---- 5、关闭窗⼝前卸载控件
Private Sub Form_Unload(Cancel As Integer)
Controls.Remove("MapView")
Set oControl = Nothing
End Sub
---- 6、特别注意
---- 通过Controls.Add⽅法添加的ActiveX控件⼀定不能在该⼯程中有该控件的任何引⽤,否则系统将出错。
---- 四、⼩结
---- 通过使⽤动态加载ActiveX控件使⽤庞⼤的应⽤程序变得很⼩,将不同的ActiveX控件进⾏各种组合,使应⽤程序更加灵活多变,如您的应⽤系统要处理三⼗种门禁,⽽某个具体的⽤户可能只有⼀种或两种门禁,根本没必要⾸先将所有门禁包含到应⽤中,可将各个门禁独⽴封装,只安装注册需要的组件,就象Windows的⾃定义安装⼀样。微软的未来技术基础是分布式的组件技术(DCOM),将会把代码的重⽤发挥得淋漓尽致。您不妨试⼀试动态加载,也许会产⽣令您惊喜的效果!
---- 本代码在Win98、VB6.0(英⽂版)上编译、运⾏。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论