Corso di Visual C++

La cattura del mouse

 

Prima di parlare della cattura del mouse vorrei però spiegarvi il significato del messaggio WM_NCHITTEST.

Questo messaggio viene inviato dal Windows prima di inviare un messaggio del mouse dell'area client o non client. Nell'implementazione di default della funzione, che riceve solo un parametro di tipo CPoint, il Windows in base al valore di questo parametro decide di inviare un messaggio del mouse dell'area client o non client.

Un override simpatico della funzione potrebbe essere quello di permettere il trascinamento della finestra non solo per la barra del titolo, ma anche per l'area client. Per fare ciò bisogna innanzitutto recuperare il codice di nHitTest, tramite CFrameWnd::OnNcHitTest (CPoint ), visto che non viene passato alla nostra funzione, ma è il valore che dovremmo restituire. Se questo non è di tipo HTCLIENT, si procede al ritorno del valore nHitTest recuperato, in caso contrario questo viene sostituito dal codice HTCAPTION:

 

UINT CMainFrame::OnNcHitTest ( CPoint point )

{

UINT nHitTest = CFrameWnd::OnNcHitTest (point); //richiamo versione di default

if (nHitTest == HTCLIENT )

nHitTest=HTCAPTION;

return nHitTest;

}

Semplice vero? Si, ma anche carino!.

Veniamo ora al sodo e vediamo come effettuare la cattura del mouse.

Come già anticipato brevemente in una recente puntata, il problema nasce dal fatto che l'applicazione una volta ricevuto un messaggio che notifica l'avvenuta pressione di un tasto del mouse, non necessariamente riceverà la notifica dell'avvenuto suo rilascio. Ciò perché la pressione potrebbe avvenire all'interno della finestra, mentre il rilascio al suo esterno. Questo inconveniente può risultare alquanto grave per alcune applicazioni.

Pensate ad esempio ad un'applicazione che disegna linee in modo interattivo: una volta cliccato su un punto si inizia il disegno di una 'rubber band' o linea ad elastico che viene continuamente cancellata e aggiornate in dipendenza della posizione del mouse ( tenendo contemporaneamente premuto il pulsante ). Nel momento in cui viene rilasciato tale pulsante, la rubber band viene cancellata ed al suo posto viene disegnata l'effettiva linea finale.

Cosa succederebbe se il programma non ricevesse mai la notifica di rilascio del pulsante? Probabilmente entrerebbe in uno stato inconsistente di errore e non voluto ( magari non disegnerà mai la linea finale e rimarrà sullo schermo la rubber band ).

Per evitare ciò nel momento in cui si ha bisogno di avere la certezza di ricevere il messaggio di pulsante rilasciato, si richiama la funzione CWnd::SetCapture().

Questa funzione fa si che la finestra riceva i messaggi WM_MOUSEMOVE e WM_XBUTTONUP anche quando il cursore è al suo esterno. Con l'avvento di Win32 c'è però da osservare che anche se il mouse è catturato, ma il pulsante è stato rilasciato, la finestra non riceve alcun messaggio da tale dispositivo. In tal caso infatti se un'applicazione catturasse il mouse e non lo rilascerebbe più, nessun altra applicazione del sistema potrebbe più rispondere ai suoi eventi ( una specie di regola antitrust ).

In genere, il posto migliore per catturare il mouse è nel gestore di pulsante premuto della finestra: OnXButtonDown; il posto migliore per rilasciarlo è nel gestore di pulsante rilasciato: OnXButtonUp. In tale funzione prima di effettuare il rilascio con CWnd::ReleaseCapture() è buona educazione controllare se siamo noi la finestra che detiene la cattura e ciò può essere fatto con la funzione CWnd::GetCapture(). Tale funzione ritorna un puntatore CWnd alla finestra che detiene la cattura del mouse oppure NULL se il mouse non è catturato.

Quindi in OnXButtonUp vedremo un codice del genere:

if (GetCapture() == this)

ReleaseCapture();

Nella prossima puntata vedremo subito in azione la cattura del mouse con un semplice programma di tracciamento di linee con le rubber band.

Intanto provate a scriverlo da voi; suggerimento: per cancellare la vecchia linea e disegnare la nuova potrebbe risultare utile la funzione CDC::SetROP2 () e selezionare la modalità di disegno R2_NOT.

Non dico di più, alla prossima.

 

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