vs2017开发ActiveX(主讲OCX)(四)、绘制ActiveX控件


参考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容器中。

在“ 控制”菜单上,单击“ 绘制图元文件”。

将出现一个单独的窗口,其中显示元文件。您可以更改此窗口的大小以查看缩放如何影响控件的图元文件。您可以随时关闭此窗口。

posted @ 2019-06-18 15:37  SunkingYang  阅读(1212)  评论(0编辑  收藏  举报