最初显示或重绘ActiveX控件时,它们遵循与使用MFC开发的其余应用程序相似的绘制过程,但有一个重要区别:ActiveX控件能够处于活动状态或非活动状态。web
ActiveX控件容器中的子窗口表示活动控件。与其余窗口同样,它在接收WM_PAINT消息时负责绘制自身。控件的基类COleControl在其OnPaint函数中处理此消息。此默认实现调用OnDraw控件的功能。设计模式
非活动控件的绘制方式不一样。当控件处于非活动状态时,其窗口要么不可见,要么不存在,所以没法接收绘制消息。相反,控件容器直接调用控件的OnDraw功能。这与活动控件的绘制过程不一样,由于OnPaint永远不会调用成员函数。app
如前面段落中所讨论的,ActiveX控件的更新方式取决于控件的状态。可是,由于框架OnDraw在两种状况下都调用成员函数,因此在此成员函数中添加大部分绘制代码。框架
该OnDraw成员函数处理控制绘画。当控件处于非活动状态时,控件容器调用OnDraw,传递控件容器的设备上下文和控件占用的矩形区域的坐标。svg
框架传递给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功能。spa
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容器中。
在“ 控制”菜单上,单击“ 绘制图元文件”。
将出现一个单独的窗口,其中显示元文件。您能够更改此窗口的大小以查看缩放如何影响控件的图元文件。您能够随时关闭此窗口。