📄 18.1.2 mfc activex controlwizard.txt
字号:
18.1.2 MFC ActiveX ControlWizard
下面,我们利用 VC++编写一个ActiveX控件,这可以利用MFC ActiveX ControlWizard 为我们生成一个ActiveX控件程序的框架。MFC为ActiveX控件的开发提供了很好的支持,对 ActiveX来说,它的底层实际上是采用 COM技术实现的,但是利用 MFC ActiveX Con位olWizard,即使对COM不了解,我们也可以开发出一个功能很完善的ActiveX控件。
本例将开发一个时钟控件。在VC++开发环境中,选择【File\New】菜单项,在打开的对话框上选择Projects选项卡,并在列表框中选择MFC ActiveX ControlWizard,工程名设置为: Clock。单击【OK】按
18.4所示。
图 18.4 MFC ActiveX ControlWizard向导的第一步
该界面上有四个选工页。前面己经提过,一个文件中可以包含多个ActiveX控件,这里,第一个选项的作用就是询问用户该工程中将要提供的控件数目。接下来,该界面询问用户
该工程中的控件是否想要指定运行时许可。我们花费大量的时间开发了一个功能很强的控件,当然不希望其他人免费使用这个控件,那么在编写这个控件之前,就可以选择生成一个运行时许可,这样的话,其他人即使拿到这个控件,但是如果没有许可,仍将无法使用,只有得到许可后才能使用。最后两个选项分别询问用户是否生成源文件注释,以及是否生成帮助文件。本例中,对这些选项都保持默认选择。
单击【Next】按钮,进入MFC ActiveX ControlWizard向导的第二步,如图 18.5所示。这一步可以让用户编辑自动生成的类的名称和文件的名称,如果需要这么做,用户可以单击【EditNames】按钮,即可出现如图 18.6所示的对话框,在该对话框中就可以实现类的名称和文件的名称的修改。本例都保持默认设置不变。
图 18.5 MFC ActiveX ControIWizard向导的第二步
图1 8.6 编辑类的名称和文件名对话框
在如图 18.5所示的对话框中,下面的那些复选框选项是用来指定控件的特性的。本例保持默认设置不变。单击【Finish】按钮,就创建了一个MFC ActiveX控件工程。在ClassView选项卡上,我们可以看到利用MFC ActiveX ControlWizard向导创建的工程自动生成了三个类,如图 18.7所示。
图 18.7利用 MFC ActiveX ControlWizard向导创建的工程中的类
其中 CClockApp类派生于 COleControlModule类,而后者的派生层次结构如图 18.8所示。
可以看到, COleControlModule类是从CWinApp类派生的,所以可以把该类看作是一个应用程序类,它的实例表示了控件程序本身。也就是说,本例中的CClockApp类就相当于前面创建的单文档应用程序的应用程序类。
CClockCtrl类派生于COleControl类,后者的派生层次结构如图 18.9所示。
图 18.8 COleControlModule类派生层次结构图 18.9 COleCon町01类派生层次结构
可以看到, COleControl类是从CWnd类派生的,因此,它也是一个窗口类,相当于单文档应用程序中的主窗口类,或者视类,那么对控件窗口进行的操作都将在CClockCtrl类中完成。在该类中,可以看到它提供了一个OnDraw函数,当控件窗口发生重绘时就会调用这个函数。如果控件需要输出图形,就可以在这个函数中编写相应的实现代码。
如例 18-1所示代码是CClockCtrl类头文件中的部分内容,从中可以看到,在该文件中不仅提供了一个消息映射,还提供了一个调度映射和事件映射。其中调度映射是 MFC提供的一种映射机制,主要是为了让外部应用程序可以方便地访问控件的属性和方法,而. 事件映射也是MFC提供的一种映射机制,让控件可以向包含它的容器发送事件通知。稍后我们为Clock控件添加方法和属性时就会用到这两个映射。
例 18-1
// Message maps
// {{AFX_MSG(CClockCtrl)
// NOTE -ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
// }}AFX_MSG
DECLARE_MESSAGE_MAP()
// Dispatch maps
// {{AFX_DISPATCH(CClockCtrl)
// NOTE -ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see i n these blocks of generated code !
// }}AFX_DISPATCH
. DECLARE_D工 SPATCH_MAP ( )
// Event maps
// ({AFX_EVENT(CClockCtrl) // NOTE -ClassWizard will add and remove member functions here . / / DO NOT ED工 T what you see in t hese blocks of generated code !
// }}AFX_EVENT
DECLARE_EVENT_MAP()
.
CClockPropPage类派生于 COlePropertyPage类,后者的派生层次结构如图 18.10所示。
图 18.10 COlePropertyPage类派生层次结构
可以看到, COlePropertyPage类派生于 CDialog类,它以一种类似于对话框的图形界
面显示一个自定义控件的属性。也就是说, CClockPropPage类是用来显示 Clock控件的属
性页的。既然 CClockPropPage类是一个对话框类,那么就应该有一个对话框资源与之相
关联。在该类的头文件中,可以看到下面这条语句,说明该类与一个 ID为 IDD
PROPPAGE_CLOCK的对话框资源相关联 :
enum { IDD =IDD_PROPPAGE_CLOCK };
另外,读者可以看到在上面的图 18.7中,在上述介绍的三个类的上面还有两项内容:
DClock和\DClockEvents,它们的前面都有一个像平放着的小勺一样的图标(\),该图标表示对应的项是接口,接口是控件与外部程序进行通信的协议。可以把接口看作是函数的集合,外部程序通过这个接口所暴露出来的方法去访问控件的属性和方法。实际上,可以把接口看作是一个抽象基类,在此接口中定义的所有函数都是纯虚函数,这些函数的实现是在 CClockCtrl类中完成的。 MFC通过底层的封装,让 CClockCtrl类继承自接口:\DClock,所以通过该接口调用的函数实际上调用是 CClockCtrl类中真正实现的函数。 ActiveX控件中的接口与计算机硬件的接口是类似的,例如,在计算机硬件中,主板与显卡间的通信是通过主板上的插槽完成的,这个插槽就是主板与显卡进行通信的接口,一旦我们制定了这个接口,就可以任意地选择一块主板与一块显卡进行通信。因为该接口是标准的,所以选择任一厂商生产的主板,任一厂商生产的显卡都是可以的,只要它们的接口遵从共同的标准。主板通过该接口所暴露出来的方法去调用显卡的显示功能,而显卡需要实现该接口所暴露出来的方法。显卡就相当于这里的 ActiveX控件,而主板就相当于与控件通信的外部容器。如果两个通信实体要通过接口进行通信,那么肯定是其中的一个实体实现该接口所显露出来的方法,而另一个实体通过接口调用这些方法。这里,就是 ActiveX控件实现接口所暴露出来的方法,而容器调用这些方法。关于接口的底层实现,需要了解一些 COM的基本知识,读者如感兴趣的话,可以自行查看相关资料。本例中,因为 MFC
提供的封装,所以底层的细节是看不到的。但是,如果采用 COM(可以采用 ATL,即活动模板库)来编写ActiveX控件的话,那么这些底层的通信细节是可以看到的。
这里,我们先利用Build命令生成Clock控件程序,然后在该工程所在目录下的Debug目录下,可以看到生成了一个 Clock.ocx文件,这就是程序生成的 ActiveX控件文件。在使用时,只需将这个文件传递给使用方,经过注册后就可以使用该控件了。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -