1. 容器:可以在其上拖放ActiveX控件,如VB调用MFC编写的ActiveX控件时候,VB就是一个容器。
2. MFC通过ClassWizard创建的工程有以下模块:
CApp:应用程序类
CCtrl:相当于单文档的程序中CView类,主要对窗口的操作在这个类中完成。
CPropPage:控件的属性页
接口(Interface):它是一个抽象基类,其中写的方法都是虚函数,所有虚函数的实现放在CCtrl中。外部程序调用接口中方法,其实际调用的就是CCtrl中实现的类。接口底层实现的细节是由COM的技术实现的,MFC对其进行了封装。
3. ActiveX控件的调试工具:VC的安装目录下有一个程序TSTCON32.EXE。
4. 控件的注册的通用方法是Regsvr32,其实这个程序也是调用控件内部的DllRegisterServer方法实现对控件中的信息添加到注册表中。反注册函数DllUnregisterServer的原理也是有的。这两个函数在创建的工程下Globals。
5. ActiveX控件的四种属性:
Ø Stock:为每个控件提供的标准属性,如字体或颜色。详细信息详细信息学习型详细信息详细信息 嫩
Ø Ambient:围绕控件的环境属性——已被置入容器的属性。这些属性不能被更改,但控件可以使用它们调整自己的属性。
Ø Extended:这些是由容器处理的属性,一般包括大小和在屏幕上的位置。
Ø Custom:由控件开发者添加的属性。
6. 如果当前调试目录下的Activex控件被其它程序在使用的状态下的话,再次编译该ActiveX控件程序将出现无法对控件进行写入的错误。所以再次在VC中调试该控件的时候,一定要确保该目录下的控件没有被别的程序(像VB)所添加为控件。
7. 为控件添加系统属性(需要在其它IDE中有相应设置的属性设置框,如在VB中的右侧属性就是):classwizard->automation。在classname中选择CCtrl类,然后点击add property按钮添加属性。
本例中一设置控件的背景色和文字的前景色举例:
a. 按上述所说的方法添加BackColor和ForeColor属性
b. 在CCtrl的OnDraw函数中添加如下代码:
CBrush brush(TranslateColor(GetBackColor())); //得到用户选择的背景颜色,将它设置为画刷的颜色
pdc->FillRect(rcBounds,&brush);
pdc->SetBkMode(TRANSPARENT); //将文字的背景设置成透明的
//pdc->SetBkColor(); //设置文本的背景颜色
pdc->SetTextColor(TranslateColor(GetForeColor())); //得到用户选择的前景色,并将之设置字体的前景色
注:ActiveX控件的调试也可以放在VB中进行,像设置前景色,背景色之类的操作比较方便。方法为在VB的左侧控件面板上右键选择添加部件。
8. 在属性页中添加系统属性(以添加颜色属性页为例):
在CCtrl源文件中找到如下的宏代码:
BEGIN_PROPPAGEIDS(CClockCtrl, 1)
PROPPAGEID(CClockPropPage::guid)
END_PROPPAGEIDS(CClockCtrl)
说明:guid是一个全局的唯一标识符号,是一个128位的整数,用来唯一的标识一个组件或接口。
添加代码:PROPPAGEID(CLSID_CColorPropPage) //添加颜色属性页面,其中CLSID_CColorPropPage为颜色属性页的全局唯一标识符
将BEGIN_PROPPAGEIDS中1改为2。注意:如果添加了属性页,一定要将属性页的数量随之增加。(添加颜色属性页后,在VB中调用的时候,将控件拖动到窗口上上也是成功的,但点击右键属性的时候,显示“类没有注册,查找具有CLSID的对象”这样一个错误,但将程序release后发现在别的MFC程序中调用没有发生问题。)
9. 添加自定义属性:在此处以修改时钟的时间间隔为例。步骤为classwizard->automation,在classname中选择CCtrl类,然后点击add property按钮添加属性。在External Name中添加属性名称Interval,这个名称就是在其它编译环境中控件所拥有的属性;类型选择short;Variable Name为在CCtrl源文件中创建的成员变量;Notification function为通知函数,即用户修改属性后,对应的成员变量会拿到这个值,然后就可以在这个通知函数将处理了。
通知函数中的代码如下:
if(m_interval<0 || m_interval>6000)
{
m_interval=1000;
}
else
{
m_interval=m_interval/1000*1000; //取整
KillTimer(1); //将老的Timer关闭
SetTimer(1,m_interval,NULL);
}
用VC编译环境自带的ActiveX控件测试容器对自定义属性进行测试:
a. 添加ActiveX控件
b. 选择菜单:control->invoke methods(调用方法)->method name下拉式列表中选择对应的属性值,其中分为得到属性值,则选择PropGet,设置属性值,则选择PropSet,在Parameter中填写我们想使用的属性值,点击set value按钮,在点击Invoke按钮
10. 在属性页中添加自定义属性设置:
还是以上述时间的间隔举例。在对话框资源中在属性对话框上添加文本框,此用来接收用户输入的间隔时间,给此文本框添加成员变量,在添加成员对话框的最下方有个下拉列表:optional property name,在这里填写属性的外部名称,Interval,即可,该过程不需要写一行代码即可实现。(在实际例子中点击控件右键属性的时候发生一个致命错误,点击忽略,发现结果还是正确的)
11. 给控件添加方法:
classwizard->Automation->Add Method->External Name(外部被调用时候所使用的名称),向导会自动在CCtrl添加相应的方法,在其中实现就可以了。
调试方法是采用自带的ActiveX控件测试容器,control->invoke methods(调用方法)->method name下拉式列表中选择对应方法名称,点击Invoke即可。
12. 给控件添加事件:
事件分为系统标准事件(如click等)和自定义事件。
在ClassView中右键点击_DClockEvents,选择添加事件,或者用ClassWinzard对话框上选择ActiveX Event也可。添加完成后双击_DClockEvents,进入源代码,发现两个接口之间的区别:
[default] dispinterface _DClock;
[default, source] dispinterface _DClockEvents;
事件前面多了一个source,这表明事件是一个源接口,这表明控件将用这个源接口向容器来发送通知事件,这个接口中实现的代码需要用户在容器上编写,而不是在控件内部。
a. 标准事件:
在ClassView中右键点击_DClockEvents,选择添加事件,在Add Event对话框上选择External Name下拉列表,选择标准事件,如click,这样就完成了对已存储事件的创建。
调试方法可以在VB窗体中添加控件,双击按钮,选择事件下拉选择列表,发现click事件,在其中添加想实现的内容就可以了。
b. 自定义事件
在ClassView中右键点击_DClockEvents,选择添加事件,在Add Event对话框上选择External Name,填写自己想创建的外部使用的事件名称。创建完成后发现CCtrl的类视图中添加了一个事件映射:FireEventName(eventname为自定义事件的外部名称)。然后在想触发该事件的地方调用FireEventName,以此通知容器中的控件相应的事件可以被触发了,然后用户可以在容器中编写相应的代码。
13. 控件上子定义属性设置的长期有效性:
对于自定义属性值,如果在VB程序中设置好了值后,关闭工程,当再次打开工程的时候,发现原先设置好的属性值没有被保存下来。
在CCtrl类中的DoPropExchange方法中提供了属性值保存的长期有效性,在其中可以调用以PX打头大方法让用户自定义的属性值长期有效。调用哪种PX打头的方法取决于自定义属性所对应的内部成员变量的类型,这里以PX_SHORT举例,第一个参数是DoPropExchange方法中参数指针,第二个参数是属性的外部名称,第三个是属性所对应的内部成员变量名称。第四个是属性的默认填充值。
还有一个问题,对于自定义的属性,发现如果在属性页中对属性值进行了修改,但在容器的对应属性框中该值没有相应的改变,但系统属性是可以的。在属性通知方法OnIntervalChanged内调用BoundPropertyChanged方法即可,参数是属性ID,可以在类视图中双击属性名称即可看到(id(XXX),XXX即为属性ID)。
14. 检测容器的环境属性:
检测控件是在容器的运行模式还是在设计模式下可调用方法:AmbientUserMode。关于ActiveX的详细学习可以参考MSDN中COleControl页,点击页面下方的ActiveX链接。
15. VC调用ActiveX控件:
方法一:直接在对话框上右键选择Insert ActiveX Control
方法二:菜单project->add to project->component and controls,选择已经注册的ActiveX控件。向导会自动添加一个关于控件的类,在该类中有ActiveX控件定义好的属性和方法,它Create方法可以动态创建一个ActiveX控件,其操作过程很动态创建button很类似。至于给控件添加事件,可以在控件上右键选择Event即可。