Corso di Visual C++

Gestione efficiente delle scrollbar III

 

In questo articolo termineremo il problema della gestione manuale delle scrollbar e vedremo subito come implementare la funzione OnDraw.

void CPrg20View::OnDraw(CDC* pDC)

{

CFont MyFont,*pOldFont;

LOGFONT lf;

memset(&lf, 0, sizeof(LOGFONT)); // azzera tutti i membri della struttura

lf.lfHeight = -m_nFontHeight;

strcpy(lf.lfFaceName, "Times New Roman"); // scelta tipo carattere

VERIFY(MyFont.CreateFontIndirect(&lf)); // crea il font dalla struttura LOGFONT

pOldFont=pDC->SelectObject(&MyFont); // seleziona il font nel contesto di dispositivo ( DC )

 

pDC->SetWindowOrg(0,m_nScrollPos);

for (int i=0; i<m_nNumRighe; i++)

{

if (i%3 == 0)

pDC->SetTextColor(RGB(0,0,255)); // scegliamo il colore blu

else if (i%3 == 1)

pDC->SetTextColor(RGB(255,0,0)); // scegliamo il colore rosso

else // è possibile eliminare questo ramo dell'if ( lasciato per chiarezza )

; // inutile settare il colore per la riga vuota

pDC->TextOut(5,i*m_nFontHeight,m_strTesto[i]); // scriviamo il testo

}

pDC->SelectObject(pOldFont); // ripristiniamo il contesto di dispositivo

}

Questa funzione è veramente molto semplice: inizialmente creiamo un oggetto CFont, poi verifichiamo la sua corretta allocazione e quindi settiamo l'origine della finestra. Questa operazione è molto importante perchè ci consente di vedere la giusta porzione della finestra come indicato dalla posizione della casella di scorrimento.

Faccio notare che questa funzione non è ottimizzata perché ogni volta che viene chiamata disegna sempre tutte le righe, anche quelle non visibili ( almeno ci prova! ).

Nel ciclo di disegno distinguiamo le righe per dare loro un colore diverso, alla fine ripristiniamo il contesto di dispositivo con il vecchio oggetto CFont.

Provate ora ad implementare una funzione che sia ottimizzata per disegnare solo le linee effettivamente visibili, ma se proprio non ci riuscite, guardate questa mia versione in cui dovete solo eliminare il vecchio ciclo for ed inserire il seguente codice:

int start=m_nScrollPos/m_nFontHeight; // prima riga della pagina

int end = start + m_nPageHeight/m_nFontHeight; // ultima riga della pagina

for (int i=start; i<=end,i<m_nNumRighe; i++)

{

if (i%3 == 0)

pDC->SetTextColor(RGB(0,0,255)); // scegliamo il colore blu

else if (i%3 == 1)

pDC->SetTextColor(RGB(255,0,0)); // scegliamo il colore rosso

else

; //inutile settare il colore per la riga vuota

pDC->TextOut(5,i*m_nFontHeight,m_strTesto[i]); // scriviamo il testo

}

Semplice vero? Eppure la differenza di prestazioni già diventa percepibile quando si effettua lo scrolling con la casella di scorrimento!

Con questo articolo abbiamo terminato la trattazione delle barre di scorrimento inserite manualmente in una vista.

Dovete però sapere che c'è anche un modo molto più semplice di fare tutto ciò ( e ora lo dico, eh! ) e cioè utilizzare come classe della vista una non derivata da CView, bensì da CScrollView.

Questo accorgimento ci risparmia un bel po' di codice da scrivere, vediamo brevemente le differenze sostanziali.

Innanzitutto creiamo un nuovo progetto denominato Prg22, all'ultimo passo selezionate però come classe base della vista, non CView bensì CScrollView.

In questo progetto non servirà più mappare il messaggio WM_VSCROLL perché la classe vista lo fa per noi, inoltre potremmo non agganciare neanche il messaggio WM_SIZE se non volessimo che la dimensione della pagina si adatti alla dimensione dell'area client.

Per settare le dimensioni totali, di pagina e di linea di una CScrollView si utilizza la funzione SetScrollSizes, che funziona un po' come SetScrollInfo; il suo prototipo è il seguente:

void SetScrollSizes( int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault );

Il primo parametro è il tipo di mappatura che si utilizza, gli altri sono oggetti CSize che indicano le varie dimensioni. Se non si specificano quelle di pagina e di linea, queste diventano rispettivamente 1/10 sizeTotal ed 1/10 di sizePage.
Per nascondere una barra basta lasciare a 0 le varie componenti CSize che non interessano.

Il nuovo gestore OnSize diventa il seguente:

void CPrg22View::OnSize(UINT nType, int cx, int cy)

{

CScrollView::OnSize(nType, cx, cy);

int m_nMax=m_nNumRighe*m_nFontHeight;

SetScrollSizes ( MM_TEXT, CSize (0,m_nMax), CSize (0,cy), CSize (0,m_nFontHeight) );

}

Facile vero?

Le altre funzioni sono quasi tutte le stesse del progetto Prg20; le differenze sono le seguenti:

1) La scomparsa della chiamata a SetWindowOrg in OnDraw, infatti questa chiamata è fatta direttamente dal framework.

2) Ho spostato le inizializzazioni delle variabili nel costruttore di classe perché è un modo più pulito di programmazione 3) Ho eliminato la variabile m_nScrollPos perché ora per avere la posizione dell'origine della vista utilizziamo la funzione membro GetScrollPos.

Per scaricare il nuovo progetto, clicca qui. Scarica Prg22.zip

Comunque il tempo investiro con le ultime tre lezioni non è andato sicuramente perso, perchè sapere quelle cose vi tornerà sicuramente molto utile in alcuni casi particolari che vedremo in seguito.

 

Torna all'indice Generale del corso di Corso di Visual C++ di Software Planet