Partilhar via


Otimizando o desenho de controle

Quando um controle é instruído a desenhar a si mesmo em um contexto de dispositivo fornecido por contêiner, ele normalmente seleciona objetos de GDI (como canetas, pincéis e fontes) no contexto do dispositivo, executa as operações de desenho e restaura os objetos de GDI anteriores. Se o contêiner tiver vários controles que devem ser desenhados no mesmo contexto do dispositivo e cada controle selecionar os objetos de GDI necessários, tempo poderá ser economizado se os controles não restaurarem individualmente os objetos selecionados anteriormente. Depois que todos os controles forem desenhados, o contêiner poderá restaurar automaticamente os objetos originais.

Para detectar se um contêiner dá suporte a essa técnica, um controle pode chamar a função membro COleControl::IsOptimizedDraw. Se essa função retornar TRUE, o controle poderá ignorar a etapa normal de restauração dos objetos selecionados anteriormente.

Considere um controle que tem a seguinte função (não otimizada) 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);
}

A caneta e o pincel neste exemplo são variáveis locais, o que significa que seus destruidores serão chamados quando eles ficarem fora do escopo (quando a função OnDraw terminar). Os destruidores tentarão excluir os objetos de GDI correspondentes. Mas eles não devem ser excluídos se você planeja deixá-los selecionados no contexto do dispositivo ao retornar de OnDraw.

Para evitar que os objetos CPen e CBrush sejam destruídos quando OnDraw terminar, armazene-os em variáveis membro em vez de variáveis locais. Na declaração de classe do controle, adicione declarações para duas novas variáveis de membro:

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

Em seguida, a função OnDraw poderá ser reescrita da seguinte maneira:

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

Essa abordagem evita a criação da caneta e do pincel sempre que OnDraw é chamado. A melhoria de velocidade tem o custo de manter dados de instância adicionais.

Se a propriedade ForeColor ou BackColor for alterada, a caneta ou pincel precisará ser criado novamente. Para fazer isso, substitua as funções membro OnForeColorChanged e OnBackColorChanged:

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

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

Por fim, para eliminar chamadas de SelectObject desnecessárias, modifique OnDraw da seguinte maneira:

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

Confira também

Controles ActiveX do MFC: otimização
Classe COleControl
Controles ActiveX do MFC
Assistente de controle ActiveX do MFC
Controles ActiveX do MFC: pintando um controle ActiveX