使用MFC开发ActiveX控件,简单明了直接。缺点是需要附带MFC的动态链接库,于是决定选用ATL进行开发。
搜索了一把,只有英文MSDN上面有开发例程,于是照葫芦画瓢,做了一遍,将其中的部分内容翻译摘录一下:
MSDN 链接:http://msdn2.microsoft.com/en-us/library/1byykx68(VS.80).aspx
第一步:创建ATL项目
使用新建项目->VC++项目->ATL,选择 ATL 项目,输入项目名字,进入创建项目向导,选择好对应的属性(动态链接库),VC2003将自动生成一个框架,内含:
项目代码(.c, .cpp),模块定义文件(.def),接口定义语言文件(.idl),注册脚本(.rgs),以及其他的资源文件等
第二步:添加一个 ATL 对象(Class)
在类视图中,在项目上点击右键,选择“添加->添加类”,在类选择框中,选择 VC++ ->ATL 中的“ATL 控件”,出现 ATL 控件向导对话框,在向导的“名称”选项卡,“简称”(Short name)中,填写你的 ActiveX 控件的名字,如PolyCtl,这个名字就是控件注册后使用的名字。其他选项基本选择默认。如果想使用,可以用鼠标悬停在相应项上查看简单说明。
在“选项”里面,选择支持“连接点”,可以让生成的控件调用外部实现接口,即执行特定页面函数的实现。
VC6 中,需要手工选择支持 IError 等接口。
第三步:设置控件的属性和实现
例程的控件是实现绘出一个正多边形,多边形的边数可以调整。并能够响应鼠标左键点击事件,点击事件将判断鼠标点击的位置,并根据情况调用两个外部实现函数。
在类视图的 IPolyCtl 上点击右键,选择“添加->添加属性”,添加一个 short 类型的属性,名字为 Sides,其他属性选默认,点击完成,向导将自动添加 get_Sides 和 put_Sides 的实现函数,这两个函数是外界取得 ActiveX 控件属性的时候被隐式调用的。
为控件类添加一个成员变量 short m_nSides 来存储多边形的边数。在类构造函数中将其初始化为 3。
在 get_Sides 和 put_Sides 中分别实现存取:
{
* pVal = m_nSides;
return S_OK;
}
STDMETHODIMP CPolyCtl::put_Sides( short newVal)
{
if (newVal > 2 && newVal < 101 )
{
m_nSides = newVal;
FireViewChange(); // 立即更新窗口
return S_OK;
}
else
return Error(_T( " Shape must have between 3 and 100 sides " ));
}
第四步:实现绘图
为了实现绘出多边形,这里用到了 sin 和 cos 函数,这两个函数包含在 C 头文件 math.h 中,所以需要添加引用 #include <math.h>
由于使用 Polygon 函数进行绘图,需要在类中添加一个点数组 POINT m_arrPoint[100];
在类中添加一个函数,用来计算指定矩形区域中多边形每个顶点的位置:
void CPolyCtl::CalcPoints( const RECT & rc)
{
const double pi = 3.14159265358979 ;
POINT ptCenter;
double dblRadiusx = (rc.right - rc.left) / 2 ;
double dblRadiusy = (rc.bottom - rc.top) / 2 ;
double dblAngle = 3 * pi / 2 ; // Start at the top
double dblDiff = 2 * pi / m_nSides; // Angle each side will make
ptCenter.x = (rc.left + rc.right) / 2 ;
ptCenter.y = (rc.top + rc.bottom) / 2 ;
// Calculate the points for each side
for ( int i = 0 ; i < m_nSides; i ++ )
{
m_arrPoint[i].x = ( long )(dblRadiusx * cos(dblAngle) + ptCenter.x + 0.5 );
m_arrPoint[i].y = ( long )(dblRadiusy * sin(dblAngle) + ptCenter.y + 0.5 );
dblAngle += dblDiff;
}
}
修改控件类的 OnDraw 函数,实现绘出多边形的效果:
{
RECT & rc = * (RECT * )di.prcBounds;
HDC hdc = di.hdcDraw;
COLORREF colFore;
HBRUSH hOldBrush, hBrush;
HPEN hOldPen, hPen;
// Translate m_colFore into a COLORREF type
OleTranslateColor(m_clrFillColor, NULL, & colFore);
// Create and select the colors to draw the circle
hPen = (HPEN)GetStockObject(BLACK_PEN);
hOldPen = (HPEN)SelectObject(hdc, hPen);
hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
// Create and select the brush that will be used to fill the polygon
hBrush = CreateSolidBrush(colFore);
SelectObject(hdc, hBrush);
CalcPoints(rc);
Polygon(hdc, & m_arrPoint[ 0 ], m_nSides);
// Select back the old pen and brush and delete the brush we created
SelectObject(hdc, hOldPen);
SelectObject(hdc, hOldBrush);
DeleteObject(hBrush);
return S_OK;
}
此时,编译运行,使用 ActiveX控件测试容器 (工具 菜单中可以直接打开)对 ActiveX 控件进行测试。
注意:由于一般情况下,项目属性的“生成后”将自动注册控件,在 Vista 下,如果想要注册 ActiveX,需要以管理员身份启动编译环境,以管理员身份进行注册。
第五步:添加事件处理
使控件响应鼠标点击并调用外部实现方法。
在第二步里面,选择了“选项->支持 连接点”的话,类视图将有一个 _IPolyCtlEvent 接口,在上面点击右键,选择“添加->添加方法”,在添加方法向导中,将返回类型设置为 void,函数名设置为 ClickIn,参数设置为 [in]long x 和 [in]long y。用同样操作添加 ClickOut 方法。
此时代码中的接口部分将类似如下代码:
{
properties:
methods:
[id( 1 ), helpstring( " 方法 ClickIn " )] void ClickIn([ in ]LONG x, [ in ] LONG y);
[id( 2 ), helpstring( " 方法 ClickOut " )] void ClickOut([ in ] LONG x, [ in ] LONG y);
};
在 VC6 中,此时需要重新编译 idl 文件,然后对类 CPolyCtl 进行右键菜单中的添加连接点(Implement Connection Points),VC2003 中,在此类创建时就已经自动绑定,不需要再次手工操作。
在类 CPolyCtl 的属性对话框中,选择消息标签,重载 WM_LBUTTONDOWN 事件,添加如下代码:
{
HRGN hRgn;
WORD xPos = LOWORD(lParam); // horizontal position of cursor
WORD yPos = HIWORD(lParam); // vertical position of cursor
CalcPoints(m_rcPos);
// Create a region from our list of points
hRgn = CreatePolygonRgn( & m_arrPoint[ 0 ], m_nSides, WINDING);
// If the clicked point is in our polygon then fire the ClickIn
// event otherwise we fire the ClickOut event
if (PtInRegion(hRgn, xPos, yPos))
Fire_ClickIn(xPos, yPos);
else
Fire_ClickOut(xPos, yPos);
// Delete the region that we created
DeleteObject(hRgn);
return 0 ;
}
编译,再测试,可一看到 ActiveX控件测试容器中,鼠标点击时产生的 ClickIn 和 ClickOut 调用。
第六步:添加属性页(懒,没做,略)
第七步:在网页中的引用
项目编译的时候,会自动产生一个文件,名字叫 PolyCtl.htm,编辑它:
< HEAD >
< TITLE > 对象 PolyCtl 的 ATL 7.0 测试页 </ TITLE >
</ HEAD >
< BODY >
< OBJECT ID ="PolyCtl" CLASSID ="CLSID:4CBBC676-507F-11D0-B98B-000000000000" ></ OBJECT >
< SCRIPT LANGUAGE ="VBScript" >
< ! --
Sub PolyCtl_ClickIn(x, y)
PolyCtl.Sides = PolyCtl.Sides + 1
End Sub
Sub PolyCtl_ClickOut(x, y)
PolyCtl.Sides = PolyCtl.Sides - 1
End Sub
-->
</ SCRIPT >
</ BODY >
</ HTML >
使用浏览器打开网页,点击其中的 ActiveX 控件,试试结果吧。