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