Trageți un formular Delphi fără bara de legendă

Cel mai obișnuit mod de a muta o fereastră este să o trageți de bara de titlu. Citiți mai departe pentru a afla cum puteți oferi capacități de glisare pentru formularele Delphi fără o bară de titlu, astfel încât utilizatorul să poată muta un formular făcând clic oriunde pe zona clientului.

De exemplu, luați în considerare cazul unei aplicații Windows care nu are o bară de titlu, cum putem muta o astfel de fereastră? De fapt, este posibil să se creeze ferestre cu o bară de titlu non-standard și chiar forme ne-dreptunghiulare. În acest caz, cum ar putea Windows să știe unde se află marginile și colțurile ferestrei?

Mesajul Windows WM_NCHitTest

Sistemul de operare Windows se bazează foarte mult pe manipularea mesajelor. De exemplu, atunci când faceți clic pe o fereastră sau un control, Windows îi trimite un mesaj wm_LButtonDown, cu informații suplimentare despre locul în care se află cursorul mouse-ului și care sunt tastele de control care sunt apăsate în prezent. Sună cunoscut? Da, acesta nu este altceva decât un eveniment OnMouseDown din Delphi.

În mod similar, Windows trimite un mesaj wm_NCHitTest ori de câte ori are loc un eveniment de mouse, adică atunci când se deplasează cursorul sau când este apăsat sau eliberat un buton de mouse.

Cod la intrare

Dacă putem face ca Windows să creadă că utilizatorul trage (a făcut clic pe) bara de titlu în loc de zona clientului, atunci utilizatorul ar putea trage fereastra făcând clic în zona clientului. Cel mai simplu mod de a face acest lucru este să „păcăliți” Windows în a crede că faceți clic pe bara de titlu a unui formular. Iată ce trebuie să faci:

1. Introduceți următoarea linie în secțiunea „Declarații private” din formularul dvs. (declarație privind procedura de gestionare a mesajelor):

 procedură WMNCHitTest (var Msg: TWMNCHitTest); mesaj WM_NCHitTest; 

2. Adăugați următorul cod în secțiunea „implementare” din unitatea formularului dvs. (unde Form1 este numele presupus al formularului):

 procedură TForm1.WMNCHitTest (var Msg: TWMNCHitTest);

începe

    mostenit;

  
dacă Msg.Result = htClient apoi Msg.Result: = htCaption;

Sfârșit; 

Prima linie de cod din handlerul de mesaje apelează la metoda moștenită pentru a obține gestionarea implicită pentru mesajul wm_NCHitTest. Partea If în procedură interceptează și schimbă comportamentul ferestrei. Acest lucru se întâmplă de fapt: când sistemul de operare trimite un mesaj wm_NCHitTest la fereastră, împreună cu coordonatele mouse-ului, fereastra returnează un cod care precizează ce porțiune de sine a fost lovită. Informația importantă, pentru sarcina noastră, se află în valoarea câmpului Msg.Result. În acest moment, avem posibilitatea de a modifica rezultatul mesajului.

Asta facem: dacă utilizatorul a făcut clic în zona clientului formularului, facem ca Windows să creadă că utilizatorul a făcut clic pe bara de titlu. În „cuvintele” obiectului Pascal: dacă valoarea returnării mesajului este HTCLIENT, o schimbăm pur și simplu pe HTCAPTION.

Nu mai există evenimente pentru mouse

Modificând comportamentul implicit al formularelor noastre, eliminăm posibilitatea Windows-ului de a vă notifica atunci când mouse-ul este peste zona clientului. Un efect secundar al acestui truc este că formularul dvs. nu va mai genera evenimente pentru mesajele mouse-ului.

Fereastră fără margini

Dacă doriți o fereastră fără margini de legendă similară cu o bară de instrumente plutitoare, setați Legenda formularului pe un șir gol, dezactivați toate BorderIcons și setați BorderStyle pe bsNone.

Un formular poate fi modificat în diverse moduri prin aplicarea codului personalizat în metoda CreateParams.

Mai multe trucuri WM_NCHitTest

Dacă te uiți mai atent la mesajul wm_NCHitTest, vei vedea că valoarea returnată a funcției indică poziția punctului fierbinte al cursorului. Acest lucru ne permite să jucăm ceva mai mult cu mesajul pentru a crea rezultate ciudate.

Următorul fragment de cod va împiedica utilizatorii să vă închidă formularele făcând clic pe butonul Închidere.

 dacă Msg.Result = htÎnchide apoi Msg.Result: = htInnume; 

Dacă utilizatorul încearcă să mute formularul făcând clic pe bara de subtitrare și glisând, codul înlocuiește rezultatul mesajului cu un rezultat care indică că utilizatorul a făcut clic pe zona clientului. Acest lucru împiedică utilizatorul să mute fereastra cu mouse-ul (opus celor făcute în cerșirea articolului).

 dacă Msg.Result = htCaption apoi Msg.Result: = htClient; 

Având componente pe o formă

În cele mai multe cazuri, vom avea unele componente pe un formular. Să spunem, de exemplu, că un obiect al Panoului se află pe un formular. Dacă proprietatea Align a unui panou este setată pe alClient, Panoul umple întreaga zonă de client, astfel încât este imposibil să selectați formularul părinte făcând clic pe el. Codul de mai sus nu va funcționa - de ce? Se datorează faptului că mouse-ul se deplasează întotdeauna peste componenta Panoului, nu din formular.

Pentru a muta formularul prin glisarea unui panou pe formular, trebuie să adăugăm câteva linii de cod în procedura evenimentului OnMouseDown pentru componenta Panoul:

 procedură TForm1.Panel1MouseDown

   (Expeditor: TObject; Buton: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
începe

    ReleaseCapture;

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

 Sfârșit; 

Notă: Acest cod nu va funcționa cu controale non-ferestre, cum ar fi componentele TLabel.