Ottimizzazione del disegno dei controlli
Quando viene richiesto a un controllo di disegnarsi in un contesto di dispositivo fornito dal contenitore, il controllo in genere seleziona gli oggetti GDI (come penne, pennelli e 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 individualmente gli oggetti precedentemente selezionati. Una volta che tutti i controlli sono stati disegnati, il contenitore può automaticamente ripristinare gli oggetti originali.
Per rilevare se un contenitore supporta questa tecnica, un controllo può chiamare la funzione membro COleControl::IsOptimizedDraw . Se questa funzione restituisce TRUE, il controllo può ignorare il normale passaggio di ripristino degli oggetti selezionati in precedenza.
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 relativi distruttori verranno chiamati quando escono dall'ambito (quando termina la funzione OnDraw
). 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 CPen e CBrush vengano eliminati definitivamente al OnDraw
termine, archiviarli in variabili membro anziché 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 viene chiamata la funzione OnDraw
. Il miglioramento nella velocità avviene a costo di mantenere dati aggiuntivi dell'istanza.
Se la proprietà ForeColor o BackColor cambia, la penna o il pennello devono essere ricreati. A tale scopo, eseguire l'override delle funzioni membro OnForeColorChanged e OnBackColorChanged :
void CMyAxOptCtrl::OnForeColorChanged()
{
m_pen.DeleteObject();
}
void CMyAxOptCtrl::OnBackColorChanged()
{
m_brush.DeleteObject();
}
Infine, eliminare le chiamate di SelectObject
non necessarie e 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);
}
}
Vedi anche
Controlli ActiveX MFC: ottimizzazione
Classe COleControl
Controlli ActiveX MFC
Creazione guidata controllo ActiveX MFC
Controlli ActiveX MFC: disegno di un controllo ActiveX