最佳控件绘制
当控件将指示将引入了由容器提供的设备上下文时,通常会选择 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 调用时,此方法避免钢笔和画笔的创建。速度提高随附维护额外的实例数据太。
如果前景色或背景色属性更改,钢笔或画笔需要重新创建。为此,请重写 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);
}
}