参考MFC ActiveX Controls: Painting an ActiveX Control
本文介绍ActiveX控件绘制过程以及如何更改绘制代码以优化过程。(有关如何通过不使控件单独恢复以前选择的GDI对象来优化绘图的技术,请参阅优化控制图。在绘制完所有控件后,容器可以自动恢复原始对象。)
本文中的示例来自MFC ActiveX控件向导使用默认设置创建的控件。
绘制控件的整个过程以及ActiveX控件向导创建的代码以支持绘制
ActiveX控件的绘制过程
最初显示或重绘ActiveX控件时,它们遵循与使用MFC开发的其他应用程序类似的绘制过程,但有一个重要区别:ActiveX控件可以处于活动状态或非活动状态。
ActiveX控件容器中的子窗口表示活动控件。与其他窗口一样,它在接收WM_PAINT消息时负责绘制自身。控件的基类COleControl在其OnPaint函数中处理此消息。此默认实现调用OnDraw控件的功能。
非活动控件的绘制方式不同。当控件处于非活动状态时,其窗口要么不可见,要么不存在,因此无法接收绘制消息。相反,控件容器直接调用控件的OnDraw功能。这与活动控件的绘制过程不同,因为OnPaint永远不会调用成员函数。
如前面段落中所讨论的,ActiveX控件的更新方式取决于控件的状态。但是,因为框架OnDraw在两种情况下都调用成员函数,所以在此成员函数中添加大部分绘制代码。
该OnDraw成员函数处理控制绘画。当控件处于非活动状态时,控件容器调用OnDraw,传递控件容器的设备上下文和控件占用的矩形区域的坐标。
框架传递给OnDraw成员函数的矩形包含控件占用的区域。如果控件处于活动状态,则左上角为(0,0),并且传递的设备上下文用于包含控件的子窗口。如果控件处于非活动状态,则左上角坐标不一定是(0,0),并且传递的设备上下文是针对包含控件的控件容器。
注意 重要的是,您的修改OnDraw不依赖于矩形的左上角等于(0,0),而是仅在传递给矩形的内部绘制OnDraw。如果绘制超出矩形区域,则可能会出现意外结果。
控件实现文件(.CPP)中的MFC ActiveX控件向导提供的默认实现(如下所示)使用白色笔刷绘制矩形,并使用当前背景颜色填充椭圆。
void CMyAxUICtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
if (!pdc)
return;
// TODO: Replace the following code with your own drawing code.
pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
}
注意 在绘制控件时,不应该假设将作为pdc参数传递给OnDraw函数的设备上下文的状态。有时,设备上下文由容器应用程序提供,不一定会初始化为默认状态。特别是,明确选择绘图代码所依赖的笔,画笔,颜色,字体和其他资源。
如何优化绘制过程
优化你的绘制代码
控件成功绘制后,下一步是优化OnDraw功能。
ActiveX控件绘制的默认实现绘制整个控件区域。这对于简单的控件来说已经足够了,但是在许多情况下,如果仅重新绘制需要更新的部分而不是整个控件,则重新绘制控件会更快。
该OnDraw函数通过传递rcInvalid提供了一种简单的优化方法,rcInvalid是需要重绘的控件的矩形区域。使用此区域(通常小于整个控制区域)可加快绘制过程。
如何使用元文件绘制控件
在大多数情况下,函数的pdc参数OnDraw指向屏幕设备上下文(DC)。然而,当打印控件的图像时或在打印预览会话期间,接收用于渲染的DC是称为“元文件DC”的特殊类型。与立即处理发送给它的请求的屏幕DC不同,元文件DC存储稍后要回放的请求。在设计模式下,某些容器应用程序还可以选择使用图元文件DC来呈现控制图像。
元数据绘图请求可以由容器通过两个接口函数进行:( IViewObject::Draw此函数也可以调用非元文件绘图)和IDataObject::GetData。当元文件DC作为参数之一传递时,MFC框架调用COleControl :: OnDrawMetafile。因为这是一个虚拟成员函数,所以在控件类中重写此函数可以进行任何特殊处理。默认行为调用COleControl::OnDraw。
要确保可以在屏幕和元文件设备上下文中绘制控件,必须仅使用屏幕和图元文件DC中都支持的成员函数。请注意,坐标系可能无法以像素为单位进行测量。
因为默认实现OnDrawMetafile调用控件的OnDraw函数,所以只使用适合元文件和屏幕设备上下文的成员函数,除非你重写OnDrawMetafile。下面列出了CDC可以在元文件和屏幕设备上下文中使用的成员函数的子集。有关这些函数的更多信息,请参阅MFC参考中的类CDC。
Arc | BibBlt | Chord |
---|---|---|
Ellipse | Escape | ExcludeClipRect |
ExtTextOut | FloodFill | IntersectClipRect |
LineTo | MoveTo | OffsetClipRgn |
OffsetViewportOrg | OffsetWindowOrg | PatBlt |
Pie | Polygon | Polyline |
PolyPolygon | RealizePalette | RestoreDC |
RoundRect | SaveDC | ScaleViewportExt |
ScaleWindowExt | SelectClipRgn | SelectObject |
SelectPalette | SetBkColor | SetBkMode |
SetMapMode | SetMapperFlags | SetPixel |
SetPolyFillMode | SetROP2 | SetStretchBltMode |
SetTextColor | SetTextJustification | SetViewportExt |
SetViewportOrg | SetWindowExt | SetWindowORg |
StretchBlt | TextOut |
除了CDC成员函数之外,还有一些在图元文件DC中兼容的其他函数。这些包括CPalette :: AnimatePalette,CFont :: CreateFontIndirect,以及三个成员函数CBrush:CreateBrushIndirect,CreateDIBPatternBrush和CreatePatternBrush。
未记录在图元文件中的函数有:DrawFocusRect,DrawIcon,DrawText,ExcludeUpdateRgn,FillRect,FrameRect,GrayString,InvertRect,ScrollDC和TabbedTextOut。由于元文件DC实际上并未与设备关联,因此不能将SetDIBits,GetDIBits和CreateDIBitmap与图元文件DC一起使用。您可以使用SetDIBitsToDevice和StretchDIBits将元文件DC作为目标。CreateCompatibleDC,CreateCompatibleBitmap和CreateDiscardableBitmap 对于元文件DC没有意义。
使用图元文件DC时要考虑的另一点是,坐标系可能无法以像素为单位进行测量。出于这个原因,所有的绘图代码应该进行调整,以适应传递到矩形OnDraw的rcBounds参数。这可以防止在控件外部意外绘制,因为rcBounds表示控件窗口的大小。
为控件实现元文件呈现后,使用Test Container测试元文件。有关如何访问测试容器的信息,请参阅使用测试容器测试属性和事件。
使用Test Container测试控件的元文件
在“测试容器”的“ 编辑”菜单上,单击“ 插入新控件”。
在“ 插入新控件”框中,选择该控件,然后单击“ 确定”。
该控件将出现在Test容器中。
在“ 控制”菜单上,单击“ 绘制图元文件”。
将出现一个单独的窗口,其中显示元文件。您可以更改此窗口的大小以查看缩放如何影响控件的图元文件。您可以随时关闭此窗口。