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


Оптимизация рисования элементов управления

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

См. также

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