更改绘图代码(ATL 教程,第 4 部分)
默认情况下,控件的绘图代码会显示一个正方形和文本 PolyCtl。 在此步骤中,你将更改代码以显示更有趣的内容。 涉及以下任务:
修改头文件
修改
OnDraw
函数添加用于计算多边形点的方法
初始化填充颜色
修改头文件
首先添加对数学函数 sin
和 cos
(用于计算多边形点)的支持,并创建一个数组来存储位置。
修改头文件
将
#include <math.h>
行添加到 PolyCtl.h 的顶部。 该文件的顶部应如下所示:#include <math.h> #include "resource.h" // main symbols
通过将以下代码添加到 PolyCtl.h,实现
IProvideClassInfo
接口以提供控件的方法信息。 在CPolyCtl
类中,将以下行:public CComControl<CPolyCtl>
替换为
public CComControl<CPolyCtl>, public IProvideClassInfo2Impl<&CLSID_PolyCtl, &DIID__IPolyCtlEvents, &LIBID_PolygonLib>
在
BEGIN_COM_MAP(CPolyCtl)
中添加以下行:COM_INTERFACE_ENTRY(IProvideClassInfo) COM_INTERFACE_ENTRY(IProvideClassInfo2)
计算多边形点后,它们将存储在
POINT
类型的数组中,因此请在 PolyCtl.h 中的定义语句short m_nSides;
之后添加该数组:POINT m_arrPoint[100];
修改 OnDraw 方法
现在应该修改 PolyCtl.h 中的 OnDraw
方法。 要添加的代码将创建用于绘制多边形的新笔和画笔,然后调用 Ellipse
和 Polygon
Win32 API 函数来执行实际绘制。
修改 OnDraw 函数
将 PolyCtl.h 中的现有
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; }
添加用于计算多边形点的方法
添加名为 CalcPoints
的方法,用于计算构成多边形周长的点的坐标。 这些计算基于传递给函数的 RECT 变量。
添加 CalcPoints 方法
将
CalcPoints
的声明添加到 PolyCtl.h 中CPolyCtl
类的IPolyCtl
公共节:void CalcPoints(const RECT& rc);
CPolyCtl
类的公共节的最后一部分如下所示:void FinalRelease() { } public: void CalcPoints(const RECT& rc);
将
CalcPoints
函数的此实现添加到 PolyCtl.cpp 的末尾: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; } }
初始化填充颜色
使用默认颜色初始化 m_clrFillColor
。
初始化填充颜色
通过将以下行添加到 PolyCtl.h 中的
CPolyCtl
构造函数,使用绿色作为默认颜色:m_clrFillColor = RGB(0, 0xFF, 0);
该构造函数现在如下所示:
CPolyCtl()
{
m_nSides = 3;
m_clrFillColor = RGB(0, 0xFF, 0);
}
生成和测试控件
重新生成控件。 如果 PolyCtl.htm 文件仍处于打开状态,请确保将它关闭,然后在“生成”菜单中单击“生成多边形”。 可以从 PolyCtl.htm 页再次查看该控件,但这次请使用 ActiveX 控件测试容器。
使用 ActiveX 控件测试容器
生成并启动 ActiveX 控件测试容器。 可以在 GitHub 上找到 TSTCON 示例:ActiveX 控件测试容器。
注意
对于涉及
ATL::CW2AEX
的错误,请在 Script.Cpp 中将行TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT );
替换为TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT.m_psz );
,将行TRACE( "Source Text: %s\n", COLE2CT( bstrSourceLineText ) );
替换为TRACE( "Source Text: %s\n", bstrSourceLineText );
。
对于涉及HMONITOR
的错误,请在TCProps
项目中打开 StdAfx.h,并将:#ifndef WINVER #define WINVER 0x0400 #endif
替换为
#ifndef WINVER #define WINVER 0x0500 #define _WIN32_WINNT 0x0500 #endif
在“测试容器”的“编辑”菜单中,单击“插入新控件”。
找到名为
PolyCtl class
的控件,然后单击“确定”。 你将看到一个包含在圆圈中的绿色三角形。
尝试遵循以下过程更改边数。 若要从“测试容器”内部修改双重接口的属性,请使用“调用方法”。
从测试容器内部修改控件的属性
在“测试容器”的“控件”菜单中单击“调用方法”。
此时会显示“调用方法”对话框。
从“方法名称”下拉列表框中选择“边”属性的“PropPut”版本。
在“参数值”框中键入
5
,单击“设置值”,然后单击“调用”。
请注意,控件不会更改。 尽管通过设置 m_nSides
变量在内部更改了边数,但这不会导致控件重绘。 如果切换到另一应用程序,然后再切换回“测试容器”,你会发现,控件已重绘并具有正确的边数。
若要更正此问题,请在设置边数后,添加对 IViewObjectExImpl
中定义的 FireViewChange
函数的调用。 如果控件在其自身的窗口中运行,FireViewChange
将直接调用 InvalidateRect
方法。 如果控件以无窗口的形式运行,则会对容器的站点接口调用 InvalidateRect
方法。 这会强制控件重绘自身。
添加对 FireViewChange 的调用
通过将
FireViewChange
调用添加到put_Sides
方法来更新 PolyCtl.cpp。 完成后,put_Sides
方法应如下所示:STDMETHODIMP CPolyCtl::put_Sides(short newVal) { if (2 < newVal && newVal < 101) { m_nSides = newVal; FireViewChange(); return S_OK; } else { return Error(_T("Shape must have between 3 and 100 sides")); } }
添加 FireViewChange
后,在 ActiveX 控件测试容器中重新生成并再次尝试打开该控件。 这一次,当你更改边数并单击 Invoke
时,应会立即看到控件的变化。
在下一步骤中,你将添加一个事件。