优化控件绘制

当控件指示将自身绘制到容器提供的设备上下文中时,它通常会将 GDI 对象(如笔、画笔和字体)选入设备上下文,执行其绘图作,并还原以前的 GDI 对象。 如果容器有多个要绘制到同一设备上下文中的控件,并且每个控件都选择所需的 GDI 对象,则如果控件不单独还原以前选择的对象,则可以保存时间。 绘制完所有控件后,容器可以自动还原原始对象。

若要检测容器是否支持此技术,控件可以调用 COleControl::IsOptimizedDraw 成员函数。 如果此函数返回 TRUE,则控件可以跳过还原以前所选对象的正常步骤。

请考虑具有以下(未优化) OnDraw 函数的控件:

void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
   CPen pen(PS_SOLID, 0, TranslateColor(GetForeColor()));
   CBrush brush(TranslateColor(GetBackColor()));
   CPen* pPenSave = pdc->SelectObject(&pen);
   CBrush* pBrushSave = pdc->SelectObject(&brush);
   pdc->Rectangle(rcBounds);
   pdc->SelectObject(pPenSave);
   pdc->SelectObject(pBrushSave);
}

此示例中的笔和画刷是局部变量,这意味着当它们超出作用域时(即函数OnDraw结束时),它们的析构函数将被调用。 析构函数将尝试删除相应的 GDI 对象。 但是,如果您打算在从 OnDraw 返回时仍让它们留在设备上下文中,则不应将它们删除。

若要防止 CPenCBrush 对象在完成后被 OnDraw 销毁,请将它们存储在成员变量而不是局部变量中。 在控件的类声明中,为两个新成员变量添加声明:

class CMyAxOptCtrl : public COleControl
{
CPen m_pen;
CBrush m_brush;
};

然后,可以按如下所示重写函数 OnDraw

void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
   CPen pen(PS_SOLID, 0, TranslateColor(GetForeColor()));
   CBrush brush(TranslateColor(GetBackColor()));
   CPen* pPenSave = pdc->SelectObject(&pen);
   CBrush* pBrushSave = pdc->SelectObject(&brush);
   pdc->Rectangle(rcBounds);
   pdc->SelectObject(pPenSave);
   pdc->SelectObject(pBrushSave);
}

此方法可避免每次调用 OnDraw 时重新创建笔和画刷。 速度提升是以维护额外的实例数据为代价的。

如果 ForeColor 或 BackColor 属性发生更改,则需要再次创建笔或画笔。 为此,请替代 OnForeColorChangedOnBackColorChanged 成员函数:

void CMyAxOptCtrl::OnForeColorChanged()
{
   m_pen.DeleteObject();
}

void CMyAxOptCtrl::OnBackColorChanged()
{
   m_brush.DeleteObject();
}

最后,若要消除不必要的 SelectObject 调用,请按如下所示进行修改 OnDraw

void CMyAxOptCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
   if (m_pen.m_hObject == NULL)
      m_pen.CreatePen(PS_SOLID, 0, TranslateColor(GetForeColor()));
   if (m_brush.m_hObject == NULL)
      m_brush.CreateSolidBrush(TranslateColor(GetBackColor()));
   CPen* pPenSave = pdc->SelectObject(&m_pen);
   CBrush* pBrushSave = pdc->SelectObject(&m_brush);
   pdc->Rectangle(rcBounds);
   if (!IsOptimizedDraw())
   {
      pdc->SelectObject(pPenSave);
      pdc->SelectObject(pBrushSave);
   }
}

另请参阅

MFC ActiveX 控件:优化
COleControl 类
MFC ActiveX 控件
MFC ActiveX 控件向导
MFC ActiveX 控件:绘制 ActiveX 控件