Compartir por


Optimizar el dibujo de controles

Cuando se indica a un control que se dibuje en un contexto de dispositivo proporcionado por el contenedor, normalmente selecciona objetos GDI (como lápices, pinceles y fuentes) en el contexto del dispositivo, realiza sus operaciones de dibujo y restaura los objetos GDI anteriores. Si en el contenedor hay varios controles que se van a dibujar en el mismo contexto de dispositivo y cada control selecciona los objetos GDI que requiere, se puede ahorrar tiempo si los controles no restauran individualmente los objetos seleccionados previamente. Una vez dibujados todos los controles, el contenedor puede restaurar automáticamente los objetos originales.

Para detectar si un contenedor admite esta técnica, un control puede llamar a la función miembro COleControl::IsOptimizedDraw. Si esta función devuelve TRUE, el control puede omitir el paso normal de restaurar los objetos seleccionados anteriormente.

Tome en consideración un control que tenga la siguiente función OnDraw (no optimizada):

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);
}

El lápiz y el pincel de este ejemplo son variables locales, lo que significa que se llamará a sus destructores cuando salgan del ámbito (cuando finalice la función OnDraw). Los destructores intentarán eliminar los objetos GDI correspondientes. Pero no deben eliminarse si planea que sigan seleccionados en el contexto del dispositivo al volver de OnDraw.

Para evitar que los objetos CPen y CBrush se destruyan cuando OnDraw termine, almacénelos en variables miembro en lugar de variables locales. En la declaración de clase del control, agregue declaraciones para dos nuevas variables miembro:

class CMyAxOptCtrl : public COleControl
{
CPen m_pen;
CBrush m_brush;
};

A continuación, la función OnDraw se puede volver a escribir de la siguiente manera:

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);
}

Este enfoque evita la creación del lápiz y el pincel cada vez que se llama a OnDraw. La mejora de la velocidad conlleva un costo adicional del mantenimiento de datos de instancia.

Si cambia la propiedad ForeColor o BackColor, es necesario volver a crear el lápiz o el pincel. Para ello, invalide las funciones miembro OnForeColorChanged y OnBackColorChanged:

void CMyAxOptCtrl::OnForeColorChanged()
{
   m_pen.DeleteObject();
}

void CMyAxOptCtrl::OnBackColorChanged()
{
   m_brush.DeleteObject();
}

Por último, para eliminar las llamadas innecesarias a SelectObject, modifique OnDraw de la siguiente manera:

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);
   }
}

Consulte también

Controles ActiveX MFC: Optimización
COleControl (clase)
Controles ActiveX de MFC
Asistente para controles ActiveX MFC
Controles ActiveX MFC: Pintar un control ActiveX