1) 创建ATL项目
使用ATL COM AppWizard 创建ATL框架为该项目命名为Circle,按照向导提示向下做,采用默认设置,即Server Type类型为Dynamic Link Library(DLL)。
2) 向ATL项目添加ActiveX控件
首先从Insert菜单项中选择New ATL Object…调出 ATL Object Wizard对话框,然后左边Category列表选择Object,右边相应地选择Full Control,如图(1)所示。按Next继续,出现 ATL Object Wizard属性对话框,如图(2),在Names选项卡中,我们只需要在Short Name 编辑框输入CircleCtl即可,其它系统就会自动给定,也可以修改,我们这里保持系统给定状态;在Attributes 选项卡中,选择 Support ISupportErrorInfo 和 Support Connection Points 两个复选框,这两项分别支持出错信息和连接点;Miscellaneous选项卡保持默认设置;Stock Properties中我们把FillColor添加到支栏中,确定之后就把该控件加到项目中了。
图1 图2
3)为ActiveX控件添加自定义属性
现在来添加Circle控件的一个基本属性——Radius。
在Workspace Windows中Class View状态下,右击 ICircleCtl接口,选择Add Property,属性类型为short,名为Radius,参数为空。系统会自动生成get_Radius和put_Radius两个成员函数。在CCircleCtl中添加m_radius变量,用来存储半径。在CCircleCtl的构造函数中将其初始化为50,并在get_Radius函数中添加*pVal=m_radius; 在put_Radius函数中添加m_radius=newVal; FireViewChange();用来及时更新视图。对于Radius的属性,我们通过修改控件的绘制代码来使它起作用。
4) 修改ActiveX控件的绘制代码实现属性交换
首先,在CCircleCtl的构造函数中对绘制圆的填充色进行初始化,将它的初始值设为红色,即m_clrFillColor=RGB(255,0, 0)。
接下来,我们需要几个全局变量来保存控件区域的信息,在CircleCtl.h中添加如下变量:
static POINT CenterPt; static long RectHt = 0; static long RectWd = 0; |
然后修改OnDraw函数,在该绘制函数中,使用 Windows API中标准的HDC、HPEN、HBRUSH以及SelectObject、Ellipse等结构和函数来实现绘制的。例如:
// 创建画笔和画刷并选中颜色画圆 hPen = (HPEN)GetStockObject(BLACK_PEN); hOldPen = (HPEN)SelectObject(hdc, hPen); hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); hBrush = CreateSolidBrush(colFore); SelectObject(hdc, hBrush); Ellipse (hdc, (CenterPt.x - m_radius), (CenterPt.y - m_radius), (CenterPt.x +m_radius),(CenterPt.y+ m_radius)); |
5) 为ActiveX控件添加事件
现在将向ATL控件中添加Click和RClick事件。如果用户在矩形区内点击,则会激发相应事件。现在要向ICircleCtlEvents接口添加Click方法,首先在“ClassView”中选中“ICircleCtlEvents”右击,选择Add Method,出现如下对话框,并按下图设置,最后点“OK”按钮就可以添加Click事件的实现方法。用同样的方法添加RClick事件,参数与Click事件一致。接下来我们要为控件实现连接点接口IConnectionPoint和连接点容器接口IConnectionPointContainer。编译好Circle.idl文件,生成对应的Circle.tlb,在“ClassView”中选中“CCircleCtl”,右击,在Popup菜单中选择“Implement Connection Point”命令,在弹出的对话框中选中“_ICircleCtlEvents”接口。在类中定义了以两个坐标为参数的Fire_Click和Fire_RClick方法,调用这两个方法就可以在控件中激发响应的事件。
最后,添加激发事件的代码,我们分别在鼠标左键和右键按下的消息响应中进行处理,激发响应的事件,例如OnLButtonDown函数部分代码如下:
WORD xPos = LOWORD(lParam); //鼠标水平坐标 WORD yPos = HIWORD(lParam); // 鼠标垂直坐标 Fire_Click (xPos, yPos); //执行触发函数 |
至此,可以在ActiveX Control Test Container中测试该控件。
网页中使用ActiveX控件
在控件生成时,系统同时生成了一个CircleCtl.htm文件,在VC编辑环境下打开该文件,在和之间加上如下的VBScript:
<SCRIPT LANGUAGE="VBScript"> <!-- Sub CircleCtl_Click(x, y) If CircleCtl.Radius <100 Then CircleCtl.Radius = CircleCtl.Radius+1 ‘半径加1 Else MsgBox(“Radius must be less than 100!”) End If End Sub Sub CircleCtl_RClick(x, y) If CircleCtl.Radius >=1 Then CircleCtl.Radius = CircleCtl.Radius-1 ‘半径减1 Else MsgBox(“Radius mustn’t be less than 0!”) End If End Sub --> </SCRIPT> |
注意保存。然后在“我的电脑”中打开该htm文件,用鼠标单击圆,半径变大,右击圆半径变小。
结束语
本文介绍了基于ATL技术以及使用该技术实现了一个简单的圆的控件CircleCtl并且介绍了其在网页中的使用。ActiveX控件作为可重用的代码组件,不仅应用广泛,还可节约开发时间。它将大量的实现细节隐藏起来,以简明的接口与用户名交互,易于使用。对ActiveX技术的研究已经成为当今软件业的热点和潮流。
----------------------------------------------------------------------------------------------------------------------------------------------------------------
简单介绍 VC2003 使用 ATL 开发 ActiveX 控件
文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c++/cppsl/2008130/98079.html
第一步:创建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 中分别实现存取:
STDMETHODIMP CPolyCtl::get_Sides(short *pVal)
{
*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 CalcPoints(const RECT& rc);
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 函数,实现绘出多边形的效果:
HRESULT CPolyCtl::OnDraw(ATL_DRAWINFO& di)
{
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 方法。
此时代码中的接口部分将类似如下代码:
__interface _IPolyCtlEvents
{
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 事件,添加如下代码:
LRESULT CPolyCtl::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
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,编辑它:
<HTML>
<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 控件,试试结果吧。
文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c++/cppsl/2008130/98079.html