Partilhar via


Otimizando o desenho de controle

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

Para detetar se um container suporta esta técnica, um controlo pode invocar a função membro COleControl::IsOptimizedDraw. Se essa função retornar TRUE, o controle pode ignorar a etapa normal de restaurar os objetos selecionados anteriormente.

Considere um controle que tenha 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 saírem do escopo (quando a OnDraw função terminar). Os destruidores tentarão excluir os objetos GDI correspondentes. Mas eles não devem ser excluídos se você planeja deixá-los selecionados no contexto do dispositivo ao retornar do OnDraw.

Para evitar que os objetos CPen e CBrush sejam destruídos quando OnDraw terminar, armazene-os em variáveis de 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 OnDraw função pode ser reescrita da seguinte forma:

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

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

Se houver uma alteração na propriedade ForeColor ou BackColor, será necessário criar novamente a caneta ou o pincel. Para fazer isso, substitua os métodos de membro OnForeColorChanged e OnBackColorChanged

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

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

Finalmente, para eliminar chamadas desnecessárias SelectObject , modifique OnDraw da seguinte forma:

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

Ver também

Controles ActiveX MFC: Otimização
Classe COleControl
Controles ActiveX MFC
Assistente de controle ActiveX MFC
Controles ActiveX MFC: Pintando um controle ActiveX