当控件指示将自身绘制到容器提供的设备上下文中时,它通常会将 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
返回时仍让它们留在设备上下文中,则不应将它们删除。
若要防止 CPen 和 CBrush 对象在完成后被 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 属性发生更改,则需要再次创建笔或画笔。 为此,请替代 OnForeColorChanged 和 OnBackColorChanged 成员函数:
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 控件