Поделиться через


Оптимизация чертежей управления

Когда элемент управления получает команду нарисовать себя в контексте устройства, предоставленном контейнером, он обычно помещает объекты 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);
}

Перо и кисть в этом примере являются локальными переменными, то есть их деструкторы будут вызываться, когда они выходят за пределы области видимости (когда функция завершается). Деструкторы попытаются удалить соответствующие объекты 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);
   }
}

См. также

Элементы ActiveX MFC: оптимизация
Класс COleControl
Элементы управления ActiveX MFC
Мастер управления ActiveX MFC
Элементы управления ActiveX MFC: отрисовка элемента управления ActiveX