*简介
ActiveX控件是一个支持IUnknown接口的普通COM对象,必须要在操作系统中注册。要使用ActiveX控件,仍然需要将其嵌入到容器的应用程序中去。
ActiveX控件可应用于数据库访问、数据监视及图形绘制等许多领域。
ActiveX控件可以用MFC或ATL进行开发。控件可以在控件窗口中进行自身描述,对事件做出响应,并通过属性和方法组成的接口进行管理。
ActiveX控件触发事件以与它的控件容器进行通信,容器也通过方法和属性与控件进行通信。
简单说一下VS2005下开发情况。
*选择VC/MFC/MFC AcitveX 项利用程序向导生成基本的程序框架。
*添加事件。
事件就是控件发出的通知消息。在用户进行各种操作时,ActiveX会发出相应的各种通知消息,告知包含该AcitveX控件的容器,用户正在进行哪些活动,从而使容器可以进一步响应用户的活动。
事件映射表集中了事件的信息,并且允许系统方便的访问和操作控件事件。此表在控件类声明的头文件中使用下面这个宏声明:DECLARE_EVENT_MAP
一旦声明了事件映射表,就必须在用户的控件的实现文件中进行定义。如下:
// 事件映射
BEGIN_EVENT_MAP(CGraphCtrl, COleControl)
//所包含的事件映射项
END_EVENT_MAP()
实现示例:
在控件的实现类下面完成,右键点击类进行事件添加。如果在.sln中添加的一个控件项目,在给控件添加事件时,向导会提示“cannot find event interface”。这种情况下,就需要手动添加事件代码。或者单独建一个控件工程。
VC.NET中的内部名称不同于VC6中的,.NET中的内部驱动函数名称默认和事件名相同,例如你添加一个ClickIn的事件,然后选择VC.NET中的内部驱动函数也是ClickIn,而在 VC6中会是Fire_CickIn.同时可以为驱动函数选择参数,如:OLE_XPOS_PIXELS x, OLE_YPOS_PIXELS y。完成后:
向导作如下添加:
BEGIN_EVENT_MAP(CMfcCirCtrlCtrl, COleControl)
EVENT_CUSTOM_ID("ClickIn", eventidClickIn, ClickIn, VTS_XPOS_PIXELS VTS_YPOS_PIXELS)
END_EVENT_MAP()
并在头文件中添加如下代码
// 调度和事件 ID
public:
enum {
eventidClickIn = 1L
};
void ClickIn(void)
{
FireEvent(eventidClickIn, EVENT_PARAM(VTS_NONE));
}
此函数是事件驱动函数,因此需要在控件内部在适当的时候调用此函数以驱动事件。
在.idl文件自动生成
[id(1)] void ClickIn(void);
这句话将ClickIn事件和标准调度ID联系起来,使容器预先知道ClickIn事件。
如果需要删除或者手动添加事件,需要手动改写上述代码。
*添加方法。
在“类视图”中,在控件接口下面选择相应的库节点,右键单击库节点进行方法的添加。MFC提供一种机制,是控件可支持库存方法和自定义方法。该机制的第一部分是由CWnd类的派生类COleControl,它实现了库存方法。第二部分是调度映射,类似于消息映射,但是它是将虚拟成员函数映射到IDispatchID上。
需要在头文件中声明调度映射:DECLARE_DISPATHC_MAP()。
同时在CPP文件中实现:
BEGIN_DISPATCH_MAP(CGraphCtrl, COleControl)
END_DISPATCH_MAP()
调度映射的主要目的是在被外部调用的方法名称和实现该方法的控件的成员函数之间建立一个对应关系。
*添加属性。
在“类视图”中,在控件接口下面选择相应的库节点,右键单击库节点进行属性的添加。
属性代表一个控件的内部状态。容器通过属性把信息传达给控件,它就是ActiveX控件的数据成员,为容器提供了接口。
属性包括库存属性和自定义属性。实现方式有stock,成员变量,Get/set方法等三种。
stock(常用属性):库存的属性实现。
成员变量:属性实现为一个成员变量和变量改变通知函数。
如:DISP_PROPERTY_NOTIFY_ID(CGraphCtrl, "pro", dispidpro, m_pro, OnproChanged, VT_BSTR)
Get/Set方法:属性有两个相关函数:一个是获取属性的Get函数,一个是设置属性的Set函数。容器通过接口中的这两个函数来访问和修改控件的属性。
如:DISP_PROPERTY_EX_ID(CGraphCtrl, "pro2", dispidpro2, Getpro2, Setpro2, VT_BSTR)
属性的定义是接口设计层次上的任务,在实际编写AcitveX控件的时候,需要为这个属性添加一个实际的内部存储变量。
控件属性在控件容器调用程序中都转化为两个函数:Set/Get。而不是属性。容器通过这两个函数来设置属性。
*实现属性表。
在使用向导创建控件项目时,向导会生成一个“属性”对话框。
默认的属性页是从COlePropertyPage类派生的。在控件的CPP文件中有关默认属性页的代码如下:
// 属性页
// TODO: 按需要添加更多属性页。请记住增加计数!
BEGIN_PROPPAGEIDS(CGraphCtrl, 1)
PROPPAGEID(CGraphPropPage::guid)
END_PROPPAGEIDS(CGraphCtrl)
其中BEGIN_PROPPAGEIDS(CGraphCtrl, 1)的第一个参数为控件的类名,第二个参数为属性页的个数。
PROPPAGEID(CGraphPropPage::guid)表示用户添加了一个自定义的属性页。CGraphPropPage表示属性页的类名,而::guid表示该属性也为用户自定义属性页。除默认属性页外,MFC还预定义了3个类的属性页,对应的类ID如下:
CLSID_CColorProPage:用户颜色属性页
CLSID_CFontProPage:用户字体属性页
CLSID_CPictureProPage:用户图形属性页。
各个属性页在属性对话框中的排列顺序是按照加入ID的顺序决定的。
在添加自定义的属性页时,也应该从COlePropertyPage继承,在上面的代码中加载该属性页,同时将计数值加1。
实现示例:
新建一个控件属性,如:ShowA。
在属性页上添加一个Checkbox控件,为该控件添加一个变量m_showA。点击确定后,在DoDataExchange()函数中生成相应代码。
修改DoDataExchange()函数,将属性页中的Checkbox控件变量与ActiveX控件的属性ShowA绑定。 为了实现这种绑定,属性表界面上的控件变量需要通过DDP_函数来将属性页中的控件所对应的值(为属性页类的成员变量)与控件的属性值进行绑定。
如:DDP_Check(pDX, IDC_CHECK_A, m_showA, _T("ShowA") );
其中:pDX为数据交换对象;第二个参数为控件属性在属性页中对应控件的ID:第三个参数为属性页的成员变量,第四个参数为ActiveX控件的属性。
另外,在DoDataExchange()函数中,还必须调用DDX_函数来实现属性页的成员变量和属性页控件之间的数据交换。
如:DDX_Check(pDX, IDC_CHECK_A, m_showA);
*控件的序列化
控件的序列化通过PX_函数实现。
如:PX_Bool(pPX,_T("ShowA"),m_showA,TRUE);
具体函数可查阅msdn。
*控件的绘制
如果控件需要绘制用户界面,那么就需要使用OnDraw()函数。在此函数中包含了相应的设备环境(DC)。
void CGraphCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
第一参数包含要在其中进行绘制的DC。第二个参数定义控件的矩形区域,包括边界。第三个参数定义控件无效的矩形区域。
MFC提供了COleControl::InvalidateControl()函数,它是强制立即绘制整个控件窗口或者只是绘制函数调用中所制定的部分区域。它在设置控件外观属性的函数中经常被调用,与CWnd::Invalidate()类似。