Ottimizzazione del disegno dei controlli
Quando viene richiesto a un controllo di disegnarsi in un contesto di dispositivo fornito dal contenitore, in genere seleziona gli oggetti GDI (come penne, pennelli e i tipi di carattere) nel contesto di dispositivo, esegue le operazioni di disegno e ripristina gli oggetti GDI precedenti. Se il contenitore ha più controlli che devono essere disegnati nello stesso contesto di dispositivo e ogni controllo seleziona gli oggetti GDI necessari, è possibile risparmiare tempo se i controlli non ripristinano i singoli oggetti precedentemente selezionati. Dopo che tutti i controlli sono stati disegnati, il contenitore può automaticamente ripristinare gli oggetti originali.
Per individuare se un contenitore supporta questa tecnica, un controllo può chiamare la funzione membro COleControl::IsOptimizedDraw. Se la funzione restituisce TRUE, il controllo può ignorare il passaggio normale di ripristino degli oggetti precedentemente selezionati.
Si consideri un controllo con la seguente funzione OnDraw (non ottimizzata):
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);
}
La penna e il pennello in questo esempio sono variabili locali e pertanto i loro distruttori verranno chiamati quando escono dall'ambito (quando la funzione OnDraw termina). I distruttori cercheranno di eliminare gli oggetti GDI corrispondenti. Ma non devono essere eliminati se si intende lasciarli selezionati nel contesto di dispositivo restituito da OnDraw.
Per impedire che gli oggetti CBrush e CPen vengano eliminati quando OnDraw completa, li si memorizzi in variabili membro anziché in variabili locali. Nella dichiarazione della classe del controllo, aggiungere le dichiarazioni per due nuove variabili membro:
class CMyAxOptCtrl : public COleControl
{
...
CPen m_pen;
CBrush m_brush;
};
È quindi possibile riscrivere la funzione OnDraw, come segue:
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);
}
In questo modo si evita la creazione della penna e del pennello ogni volta che OnDraw viene chiamato. Il miglioramento della velocità avviene al costo di mantenere dati aggiuntivi dell'istanza.
Se la proprietà BackColor o ForeColor cambia, la penna o il pennello devono essere ricreati. A tale scopo, eseguire l'override delle funzioni membro OnBackColorChanged e OnForeColorChanged :
void CMyAxOptCtrl::OnForeColorChanged()
{
m_pen.DeleteObject();
}
void CMyAxOptCtrl::OnBackColorChanged()
{
m_brush.DeleteObject();
}
Infine, eliminare le chiamate non necessarie di SelectObject, modificare OnDraw come segue:
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);
}
}
Vedere anche
Riferimenti
Creazione guidata controllo ActiveX MFC