Trascina un modulo Delphi senza la barra dei titoli

Il modo più comune per spostare una finestra è trascinarla dalla sua barra del titolo. Continua a leggere per scoprire come è possibile fornire funzionalità di trascinamento per i moduli Delphi senza una barra del titolo, in modo che l'utente possa spostare un modulo facendo clic in qualsiasi punto dell'area client.

Ad esempio, considera il caso di un'applicazione Windows che non ha una barra del titolo, come possiamo spostare una finestra del genere? In effetti, è possibile creare finestre con una barra del titolo non standard e persino forme non rettangolari. In questo caso, come fa Windows a sapere dove sono i bordi e gli angoli della finestra?

Il messaggio Windows WM_NCHitTest

Il sistema operativo Windows è fortemente basato sulla gestione dei messaggi. Ad esempio, quando si fa clic su una finestra o un controllo, Windows gli invia un messaggio wm_LButtonDown, con ulteriori informazioni su dove si trova il cursore del mouse e quali tasti di controllo sono attualmente premuti. Suona familiare? Sì, questo non è altro che un evento OnMouseDown a Delfi.

Allo stesso modo, Windows invia un messaggio wm_NCHitTest ogni volta che si verifica un evento del mouse, ovvero quando si sposta il cursore o quando viene premuto o rilasciato un pulsante del mouse.

Codice da inserire

Se riusciamo a far pensare a Windows che l'utente sta trascinando (facendo clic su) la barra del titolo anziché l'area client, l'utente può trascinare la finestra facendo clic nell'area client. Il modo più semplice per farlo è "ingannare" Windows nel pensare che stai effettivamente facendo clic sulla barra del titolo di un modulo. Ecco cosa devi fare:

1. Inserire la seguente riga nella sezione "Dichiarazioni private" del modulo (dichiarazione della procedura di gestione dei messaggi):

 procedura WMNCHitTest (var Messaggio: TWMNCHitTest); Messaggio WM_NCHITTEST; 

2. Aggiungi il seguente codice nella sezione "implementazione" dell'unità del modulo (dove Form1 è il nome del modulo assunto):

 procedura TForm1.WMNCHitTest (var Messaggio: TWMNCHitTest);

inizio

    ereditato;

  
Se Msg.Result = htClient poi Messaggio di risposta: = htCaption;

fine; 

La prima riga di codice nel gestore messaggi chiama il metodo ereditato per ottenere la gestione predefinita per il messaggio wm_NCHitTest. La parte If della procedura intercetta e modifica il comportamento della finestra. Questo è ciò che realmente accade: quando il sistema operativo invia un messaggio wm_NCHitTest alla finestra, insieme alle coordinate del mouse, la finestra restituisce un codice che indica quale parte di se stessa è stata colpita. L'importante informazione, per il nostro compito, è nel valore del campo Messaggio. A questo punto, abbiamo l'opportunità di modificare il risultato del messaggio.

Questo è ciò che facciamo: se l'utente ha fatto clic nell'area client del modulo, facciamo in modo che Windows pensi che l'utente abbia fatto clic sulla barra del titolo. In Object Pascal "parole": se il valore di ritorno del messaggio è HTCLIENT, lo cambiamo semplicemente in HTCAPTION.

Nessun altro evento del mouse

Modificando il comportamento predefinito dei nostri moduli, rimuoviamo la capacità di Windows di avvisare l'utente quando il mouse si trova nell'area client. Un effetto collaterale di questo trucco è che il modulo non genererà più eventi per i messaggi del mouse.

Finestra senza didascalia-senza bordi

Se si desidera una finestra senza bordi senza didascalia simile a una barra degli strumenti mobile, impostare la didascalia del modulo su una stringa vuota, disabilitare tutti gli BorderIcons e impostare BorderStyle su bsNone.

Un modulo può essere modificato in vari modi applicando il codice personalizzato nel metodo CreateParams.

Altri trucchi WM_NCHitTest

Se osservi più attentamente il messaggio wm_NCHitTest, vedrai che il valore di ritorno della funzione indica la posizione dell'hot spot del cursore. Questo ci consente di giocare un po 'di più con il messaggio per creare risultati strani.

Il seguente frammento di codice impedirà agli utenti di chiudere i moduli facendo clic sul pulsante Chiudi.

 Se Msg.Result = htClose poi Messaggio di risposta: = htNowhere; 

Se l'utente sta tentando di spostare il modulo facendo clic sulla barra del titolo e trascinando, il codice sostituisce il risultato del messaggio con un risultato che indica che l'utente ha fatto clic sull'area client. Questo impedisce all'utente di spostare la finestra con il mouse (al contrario di quello che stavamo facendo nell'accattonaggio dell'articolo).

 Se Msg.Result = htCaption poi Msg.Result: = htClient; 

Avere componenti in un modulo

Nella maggior parte dei casi, avremo alcuni componenti in un modulo. Diciamo, ad esempio, che un oggetto Panel si trova su un modulo. Se la proprietà Allinea di un pannello è impostata su alClient, il Pannello riempie l'intera area client in modo che sia impossibile selezionare il modulo padre facendo clic su di esso. Il codice sopra non funzionerà - perché? È perché il mouse si sposta sempre sul componente Pannello, non sul modulo.

Per spostare il nostro modulo trascinando un pannello sul modulo, dobbiamo aggiungere alcune righe di codice nella procedura dell'evento OnMouseDown per il componente Pannello:

 procedura TForm1.Panel1MouseDown

   (Mittente: TObject; Pulsante: TMouseButton;
   Maiusc: TShiftState; X, Y: intero);
inizio

    ReleaseCapture;

    SendMessage (Form1.Handle, WM_SYSCOMMAND, 61458, 0);

 fine; 

Nota: Questo codice non funziona con i controlli non di finestra come i componenti TLabel.