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