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