Sleep een Delphi-formulier zonder de ondertitelingsbalk

De meest gebruikelijke manier om een ​​venster te verplaatsen, is door het naar de titelbalk te slepen. Lees verder om erachter te komen hoe u sleepmogelijkheden voor Delphi-formulieren zonder titelbalk kunt bieden, zodat de gebruiker een formulier kan verplaatsen door ergens in het clientgebied te klikken.

Overweeg bijvoorbeeld het geval van een Windows-toepassing zonder titelbalk, hoe kunnen we een dergelijk venster verplaatsen? Het is zelfs mogelijk om vensters te maken met een niet-standaard titelbalk en zelfs niet-rechthoekige vormen. In dit geval, hoe kon Windows weten waar de randen en de hoeken van het venster zijn?

Het WM_NCHitTest Windows-bericht

Het Windows-besturingssysteem is sterk gebaseerd op de afhandeling van berichten. Als u bijvoorbeeld op een venster of een besturingselement klikt, stuurt Windows dit een wm_LButtonDown-bericht met aanvullende informatie over waar de muiscursor zich bevindt en welke bedieningstoetsen momenteel worden ingedrukt. Klinkt bekend? Ja, dit is niets meer dan een OnMouseDown-evenement in Delphi.

Op dezelfde manier verzendt Windows een wm_NCHitTest-bericht wanneer zich een muisgebeurtenis voordoet, dat wil zeggen wanneer de cursor beweegt of wanneer een muisknop wordt ingedrukt of losgelaten.

Code in te voeren

Als we Windows kunnen laten denken dat de gebruiker de titelbalk sleept (heeft geklikt) in plaats van het clientgebied, dan kan de gebruiker het venster slepen door in het clientgebied te klikken. De eenvoudigste manier om dit te doen, is Windows voor de gek houden door te denken dat u daadwerkelijk op de titelbalk van een formulier klikt. Dit moet je doen:

1. Voeg de volgende regel in het gedeelte 'Privéaangiften' van uw formulier in (verklaring van procedure voor afhandeling van berichten):

 procedure WMNCHitTest (var Msg: TWMNCHitTest); bericht WM_NCHitTest; 

2. Voeg de volgende code toe aan het gedeelte "Implementatie" van de eenheid van uw formulier (waarbij Form1 de veronderstelde formuliernaam is):

 procedure TForm1.WMNCHitTest (var Msg: TWMNCHitTest);

beginnen

    geërfd;

  
als Msg.Result = htClient vervolgens Msg.Result: = htCaption;

einde; 

De eerste coderegel in de berichtenhandler roept de overgenomen methode aan om de standaardafhandeling voor het bericht wm_NCHitTest te verkrijgen. Het gedeelte If in de procedure onderschept en wijzigt het gedrag van uw venster. Dit is wat er feitelijk gebeurt: wanneer het besturingssysteem een ​​wm_NCHitTest-bericht naar het venster verzendt, samen met de muiscoördinaten, retourneert het venster een code die aangeeft welk deel van zichzelf is geraakt. Het belangrijkste stuk informatie voor onze taak is de waarde van het veld Msg.Result. Op dit moment hebben we de mogelijkheid om het berichtresultaat te wijzigen.

Dit doen we: als de gebruiker in het clientgedeelte van het formulier heeft geklikt, laten we Windows denken dat de gebruiker op de titelbalk heeft geklikt. In Object Pascal "words": als de retourwaarde van het bericht HTCLIENT is, veranderen we dit eenvoudig in HTCAPTION.

Geen muisgebeurtenissen meer

Door het standaardgedrag van onze formulieren te wijzigen, verwijderen we de mogelijkheid van Windows om u te waarschuwen wanneer de muis zich boven het clientgebied bevindt. Een neveneffect van deze truc is dat uw formulier geen gebeurtenissen meer genereert voor muisberichten.

Bijschrift zonder rand

Als u een titelloos venster zonder rand wilt, vergelijkbaar met een zwevende werkbalk, stelt u het bijschrift van het formulier in op een lege tekenreeks, schakelt u alle BorderIcons uit en stelt u de BorderStyle in op bsNone.

Een formulier kan op verschillende manieren worden gewijzigd door aangepaste code toe te passen in de methode CreateParams.

Meer WM_NCHitTest-trucs

Als je beter naar het bericht wm_NCHitTest kijkt, zie je dat de retourwaarde van de functie de positie van de cursor hotspot aangeeft. Hierdoor kunnen we wat meer met de boodschap spelen om vreemde resultaten te creëren.

Het volgende codefragment voorkomt dat gebruikers uw formulieren sluiten door op de knop Sluiten te klikken.

 als Msg.Result = htClose vervolgens Msg.Result: = htNowhere; 

Als de gebruiker het formulier probeert te verplaatsen door op de titelbalk te klikken en te slepen, vervangt de code het resultaat van het bericht door een resultaat dat aangeeft dat de gebruiker op het clientgebied heeft geklikt. Dit voorkomt dat de gebruiker het venster met de muis verplaatst (in tegenstelling tot wat we deden bij het bedelen van het artikel).

 als Msg.Result = htCaption vervolgens Msg.Result: = htClient; 

Onderdelen op een formulier hebben

In de meeste gevallen hebben we enkele componenten op een formulier. Laten we bijvoorbeeld zeggen dat één deelvensterobject zich in een formulier bevindt. Als de eigenschap Uitlijnen van een paneel is ingesteld op alClient, vult het paneel het hele clientgebied zodat het onmogelijk is om het bovenliggende formulier te selecteren door erop te klikken. De bovenstaande code werkt niet - waarom? Dit komt omdat de muis altijd over het paneelonderdeel beweegt, niet over het formulier.

Om ons formulier te verplaatsen door een paneel op het formulier te slepen, moeten we enkele regels code toevoegen in de OnMouseDown-gebeurtenisprocedure voor het paneelonderdeel:

 procedure TForm1.Panel1MouseDown

   (Afzender: TObject; Knop: TMouseButton;
   Shift: TShiftState; X, Y: geheel getal);
beginnen

    ReleaseCapture;

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

 einde; 

Notitie: Deze code werkt niet met niet-vensterbesturingen zoals TLabel-componenten.