FAQ DelphiConsultez toutes les FAQ
Nombre d'auteurs : 124, nombre de questions : 934, dernière mise à jour : 23 octobre 2024 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).
Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.
L'équipe Delphi de Developpez.com.
- Comment mettre une image en fond de fiche ?
- Comment mettre une image en fond d'une fiche MDI ?
- Comment récupérer le numéro de version de mon application ?
- Comment réaliser une interface style Outlook ?
- Comment personnaliser la forme de sa fiche ?
- Comment modifier l'aspect des contrôles d'une fenêtre en fonction d'un état ?
- Comment empêcher la fermeture d'une fenêtre par Alt-F4 ou Close ?
- Comment masquer la fenêtre principale ?
- Comment masquer l'application dans la barre des tâches ?
- Comment ajouter une icône dans le systray ?
- Comment déplacer une fiche sans barre de titre ?
- Comment redimensionner une fiche sans bordure ?
- Comment utiliser les contrôles XP dans une application ?
- Comment réduire toutes les fenêtres ?
- Comment faire clignoter la fenêtre de l'application ?
- Comment exécuter une application distante ?
- Comment mettre une console dans une application GUI ?
- Comment insérer un fichier dans un exécutable ?
- Comment intercepter les touches du clavier sur la fiche ?
- Comment compresser un exécutable ?
- Comment réaliser des animations graphiques ?
- Comment avoir une seule instance d'une fenêtre fille dans une application ?
- Comment insérer une ressource dans un exécutable ?
- Comment modifier le texte des boutons d'un MessageDlg ?
- Comment enlever la croix de fermeture en gardant les autres icônes d'une fenêtre ?
- Comment créer des fichiers d'aide ?
- Comment temporiser, de manière non-bloquante, certaines actions ?
- Comment ajouter un contrôle dans un MessageDlg ?
- Comment renommer une section dans un fichier INI ?
- Quelle est la différence entre Width/Height et ClientWidth/ClientHeight ?
- Comment donner le style Windows 10 aux applications développées avec Delphi 7 ?
- Comment donner le style Windows 11 aux applications sous Delphi 7
On va créer une bitmap et dire à notre fiche de l'afficher dans le coin en haut à gauche. Si notre image est trop grande, elle sera tronquée, et si elle est petite, le reste de la fiche sera rempli par la couleur de fond.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var Bitmap: TBitmap; procedure TMyForm.FormPaint(Sender: TObject); begin Canvas.Draw(0, 0, Bitmap); end; procedure TMyForm.FormCreate(Sender: TObject); Bitmap := TBitmap.Create; Bitmap.LoadFromFile('MyBitmap.bmp'); end; procedure TMyForm.FormDestroy(Sender: TObject); begin Bitmap.Free; end; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | type TMDIChild=class(TForm) private FBack:TBitmap; // Contient l'image qui sera chargée en fond d'écran FFileName:string;//l'adresse de cette image procedure SetFileName(Value:string); protected procedure Paint;override; published property FileName:string read FFileName write SetFileName; end; ... procedure TMDIChild.MDIChildCreate(Sender: TObject); begin FBack:=TBitmap.Create; // On crée l'objet Bitmap qui contiendra l'image de fond FFileName:=''; end; procedure TMDIChild.MDIChildDestroy(Sender:TObject); begin FBack.Free; end; procedure Paint; begin if FFileName<>'' then Canvas.Draw(0,0,FBack); end; procedure SetFileName(Value:string); begin if (Value<>FFileName) and (FileExists(Value)) then begin FFileName:=Value; FBack.LoadFromFile(Value); Invalidate; end; end; |
Voici le code de la fenêtre MDI. Dans ce code, j'ai modifié le constructeur de la fenêtre. Ainsi, à chaque fois qu'il faut en créer une, il est nécessaire de passer le chemin d'accès à une image. Ceci n'est pas une obligation de bon fonctionnement. L'important est que la fenêtre reçoive, d'un moyen comme d'un autre, le chemin à l'image qu'elle doit afficher.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | {...} type TFS_FicheMDI = class(TForm) procedure FormDestroy(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormPaint(Sender: TObject); private FFond : TGraphic; public constructor Create(AOwner : TComponent;Chemin : String);reintroduce; end; implementation {$R *.dfm} constructor TFS_FicheMDI.Create(AOwner : TComponent;Chemin : String); begin // Création de la fiche inherited Create(AOwner); //Initialisation FFond := nil; // Si le chemin existe if (FileExists(Chemin)) then begin // Si c'est une image jpeg if ((ExtractFileExt(Chemin) = '.jpg') or (ExtractFileExt(Chemin) = '.jpeg')) then FFond := TJPEGImage.Create // Si c'est un bmp else if (ExtractFileExt(Chemin) = '.bmp') then FFond := TBitmap.Create; // D'autres tests sont possibles {...} / /Si un format a correspondu if (Assigned(FFond)) then FFond.LoadFromFile(Chemin); end; end; procedure TFS_FicheMDI.FormDestroy(Sender: TObject); begin //Penser à libérer ! TOUJOURS ! FFond.Free; end; procedure TFS_FicheMDI.FormResize(Sender: TObject); begin // Lorsque l'on redimensionne la fenêtre, Windows redessine le fond de la // fenêtre, mais uniquement la partie qui a été modifiée. // L'image étant étirée sur toute la fenêtre, il faut la redessiner // complètement. FormPaint(Sender) end; procedure TFS_FicheMDI.FormPaint(Sender: TObject); begin // Dessin de l'image sur toute la taille de la fenêtre Canvas.StretchDraw(ClientRect, FFond); end; end. |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 | procedure TFP_FormMDI.BP_CreerClick(Sender: TObject); var uneFiche : TFS_FicheMdi; begin if (BD_OuvrirImage.Execute) then uneFiche := TFS_FicheMDI.Create(Application,BD_OuvrirImage.FileName); end; |
Voici une fonction qui récupère cette information :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | function ApplicationVersion: String; var VerInfoSize, VerValueSize, Dummy: DWord; VerInfo: Pointer; VerValue: PVSFixedFileInfo; begin VerInfoSize := GetFileVersionInfoSize(PChar(ParamStr(0)), Dummy); {Deux solutions : } if VerInfoSize <> 0 then {- Les info de version sont incluses } begin {On alloue de la mémoire pour un pointeur sur les info de version : } GetMem(VerInfo, VerInfoSize); {On récupère ces informations : } GetFileVersionInfo(PChar(ParamStr(0)), 0, VerInfoSize, VerInfo); VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize); {On traite les informations ainsi récupérées : } with VerValue^ do begin Result := IntTostr(dwFileVersionMS shr 16); Result := Result + '.' + IntTostr(dwFileVersionMS and $FFFF); Result := Result + '.' + IntTostr(dwFileVersionLS shr 16); Result := Result + '.' + IntTostr(dwFileVersionLS and $FFFF); end; {On libère la place précédemment allouée : } FreeMem(VerInfo, VerInfoSize); end else {- Les infos de version ne sont pas incluses } {On déclenche une exception dans le programme : } raise EAccessViolation.Create('Les informations de version de sont pas inclues'); end; |
Des solutions à base de TPanel ou de TPageControl existent, mais elles posent le problème de l'organisation du code et de la réutilisabilité. Nous utiliserons donc les objets TFrame (cadres) qui sont une spécificité Delphi 5 et supérieur, élégants compromis entre TForm et TPanel.
1. Création du modèle
La technique principale utilisée est celle de l'héritage : après avoir créé le modèle de base FrmModele ("menu Fichier -> Nouveau cadre"), définissez-y les caractéristiques communes à tous les écrans :
- propriétés : barre de titre, couleurs, alignement, grilles, etc ;
- méthodes : Afficher.
Vous pouvez maintenant associer ce modèle à votre application ("menu Projet -> Ajouter au projet").
2. Création des écrans (Frames) par héritage
Allez à "menu Fichier -> Nouveau -> onglet 'Nom du projet' -> icône FrmModele (hériter)". Personnalisez les écrans en fonction des besoins, notamment en surchargeant la méthode Afficher pour mettre à jour les données :
Code delphi : | Sélectionner tout |
procedure Afficher; override;
3. Gestion du fenêtrage
Réservez un espace, généralement TPanel, pour servir de zone d'affichage des écrans.
Préparez vos menus de navigation et centralisez la gestion dans une seule procédure d'aiguillage.
Notre gestion étant dynamique, nous ne placerons donc pas de Frame dans la fenêtre principale à la conception. Cependant n'oubliez pas d'ajouter leur unité à la clause uses de l'implémentation ("menu Fichier -> Utiliser l'unité ...").
Une variable de la fenêtre principale
Code delphi : | Sélectionner tout |
select_frame : TFrmModele
L'aiguillage à l'affichage est illustré par le code ci-dessous :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | { destruction du frame courant } { création de l'écran avec le constructeur de la classe souhaitée } { positionnement du frame dans le panel réservé } { initialisation de son contenu } FreeAndNil(select_frame); if Sender = Button1 then select_frame := TFrmEcran1.Create(self) else if Sender = Button2 then select_frame := TFrmEcran2.Create(self) else if ... else Exit; select_frame.Parent := PanelFrame; select_frame.Afficher; |
Code delphi : | Sélectionner tout |
1 2 3 4 | procedure TFPrincipal.OnDestroy; begin FreeAndNil(select_frame); end; |
4. Création d'autres écrans
Comme à l'étape 2, dérivez un écran de TFrmModele ("menu Fichier -> Nouveau -> onglet 'Nom du projet' -> icône FrmModele (hériter)").
Puis, ajoutez son unité à la fenêtre principale.
Branchez son évènement d'appel sur la procédure commune d'aiguillage.
Insérez enfin la ligne de code suivante en l'adaptant à l'unité que vous souhaitez rajouter :
Code delphi : | Sélectionner tout |
else if Sender = ButtonN then select_frame := TFrmEcranN.Create(self)
Voilà, ce n'est pas plus compliqué, et en fait, plus vous approfondirez cette méthode, moins vous écrirez de code redondant !
Le fichier zip ci-dessous contient deux exemples d'applications :
- l'exemple 1 illustre les explications ci-dessus ;
- l'exemple 2 apporte des éléments complémentaires :
- fermeture du frame en utilisant un message Windows,
- ajout d'un 2e niveau d'héritage pour encore plus de réutilisabilité.
Cette méthode permet d'obtenir des fiches qui ne sont plus rectangulaires.
Il faut procéder en deux parties :
1. Créer une zone affichable :
À l'aide des différentes fonctions suivantes, nous devons d'abord créer une zone :
Code delphi : | Sélectionner tout |
1 2 | CreateEllipticRgn(X1,Y1,X2,Y2 : integer); CreateEllipticRgnIndirect(Rect : TRect); |
Les procédures pour générer des zones rectangulaires et rectangulaires aux coins arrondis (RoundRect) fonctionnent de la même manière, à l'aide des fonctions :
Code delphi : | Sélectionner tout |
1 2 | CreateRectRgn(X1,Y1,X2,Y2 : integer); CreateRoundrectRgn(X1,Y1,X2,Y2,rayonarrondihor,rayonarrondivert : integer); |
On peut aussi générer des zones polygonales à l'aide de :
Code delphi : | Sélectionner tout |
CreatePolygonRgn(lppt : Array Of TPoint, cPoints : integer, PolyFillMode : integer);
- lppt est un tableau regroupant les points de notre polygone ;
- cPoints indique le nombre de points dans notre polygone ;
- PolyFillMode est une constante correspondant au mode de remplissage de notre polygone.
Notre polygone est défini comme fermé : le point 0 et dernier point seront reliés.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | Var T : ARRAY [0..2]Of TPoint; i : Integer; begin For i := 0 to 2 do T[i] := Point(Random(Width),Random(Height)); { on remplit notre tableau } Rgn := CreatePolygonRgn(T,3,WINDING); { on crée notre région } end; |
2. Définir cette zone d'affichage comme zone de notre fiche :
Nous avons besoin de dire à notre fiche d'utiliser cette région. Pour cela, nous avons :
Code delphi : | Sélectionner tout |
SetWindowRgn(hWnd: HNWD, hRng: HRNG, bRedraw: LongBool): Integer
- hWnd correspond au handle de notre fiche ;
- hRng la région où afficher notre fiche ;
- bRedraw pour dire si on veut redessiner notre fiche immédiatement ou pas.
Tout ce qui sera dans cette zone sera affiché et tout ce qui en dépassera ne le sera pas.
À rajouter dans le OnCreate de la Fiche :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | Var Rgn : Hrgn; ... begin ... Rgn := CreateEllipticRgn(1,1,100,50); {Une ellipse allongée } { On peut retravailler la région ici pour personnaliser} SetWindowRgn(Handle, Rgn, true); ... end; |
À utiliser pour indiquer qu'une fiche est modifiable ou pas (en changeant la couleur des composants et leur readonly ou enabled).
Exemple d'appel, dans le FormShow d'une fenêtre :
Code delphi : | Sélectionner tout |
setAspectsControles(self,true);
Code de la fonction :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | uses Graphics, Controls, StdCtrls, TypInfo; { Paramètres : } { container : Les controls contenus dans container vont } { être modifiés en fonction de etat } { etat : si vrai, les controls de container seront modifiables } { si false, les controls de container seront en lecture seule } { trueColor : couleur attribuée aux controls de Container si etat est vrai } { falseColor : couleur attribuée aux controls de Container si etat est faux } { testTagValue: si vrai, seuls les controls ayant leur Tag à 0 seront traités } { si false, tous les controls seront traités } procedure setAspectControles(container: TWinControl; etat: boolean; trueColor : TColor = clWindow; falseColor : TColor = clBtnFace; testTagValue : boolean = true); var i : integer; couleur : array[boolean] of TColor; begin couleur[false] := falseColor; couleur[true] := trueColor; for i:= 0 to container.ControlCount - 1 do begin { si testTagValue, seuls les contrôles dont le tag est à 0 sont modifiés } { ceci permet de ne pas traiter certains contrôles en modifiant leur tag } if (not (container.Controls[i] is TLabel)) and ((not testTagValue) or (container.Controls[i].Tag = 0)) then begin { si le contrôle contient d'autres contrôles, on fait un appel récursif } if (container.Controls[i] is TWinControl) and ((container.Controls[i] as TWinControl).ControlCount > 0) then begin setAspectControles(container.Controls[i] as TWinControl, etat, trueColor, falseColor, testTagValue) end else begin { Modification de ReadOnly ou Enabled } if GetPropInfo(container.Controls[i].ClassInfo,'readonly') <> nil then setPropValue(container.Controls[i],'readonly',not etat) else if GetPropInfo(container.Controls[i].ClassInfo,'enabled') <> nil then setPropValue(container.Controls[i],'enabled',etat); { Modification de la couleur } if not (container.controls[i] is TButtonControl) and (GetPropInfo(container.Controls[i].ClassInfo, 'color') <> nil) then setPropValue(container.Controls[i],'color',couleur[etat]); end; end; { test sur le Tag } end; end; |
Il est souvent préférable d'imposer à l'utilisateur de fermer une fenêtre par le bouton "Fermer" ou "Quitter" que de le laisser fermer la fenêtre par Alt-F4 ou la croix en haut à droite. Pour bloquer cette fermeture, il faut utiliser l'évènement OnCloseQuery de la fiche : mettre CanClose à False par défaut, sauf si l'utilisateur vient d'appuyer sur un bouton "Fermer".
Dans le code ci-dessous, une variable intermédiaire va conserver l'appui sur le bouton "Fermer" :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | TForm1 = class(TForm) ... private { Déclarations privées } PeutFermer : Boolean; ... end; { A l'ouverture de la fiche on met PeutFermer à faux. } procedure TForm1.FormShow(Sender: TObject); begin PeutFermer:=False; end; {Lors de l'appui sur le bouton "Fermer" la variable PeutFermer est mis à Vrai. } procedure TForm1.BoutonFermerClick(Sender: TObject); begin PeutFermer:=True; Close; end; {A la fermeture de la fiche on teste si la fermeture est autorisée. } procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose:=PeutFermer; end; |
Pour ne pas afficher la fenêtre principale, il faut ajouter la ligne suivante dans le fichier .DPR (source du projet) :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | program Project1; uses Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} begin Application.Initialize; { Ne pas afficher la fiche principale } Application.ShowMainForm:= False; Application.CreateForm(TForm1, Form1); Application.Run; end. |
Pour masquer l'application dans la barre des tâches, il faut rendre la fenêtre 'application' invisible. Il faut utiliser la fonction ShowWindow.
Code delphi : | Sélectionner tout |
ShowWindow(Application.Handle, SW_HIDE);
Code delphi : | Sélectionner tout |
ShowWindow(Application.Handle, SW_SHOW);
Delphi ne propose pas en standard de méthode pour ajouter une icône dans la barre des tâches de Windows.
Utilisation de composants dédiés :
Il existe nombre de composants permettant de gérer une icône dans la barre des tâches. La librairie Rx en propose aussi un ; cette librairie est incluse dans la JVCL (voir le lien ci-dessous).
Utilisation de l'API :
Il est cependant possible de gérer soi-même cette icône en utilisant la fonction API suivante :
Code Delphi : | Sélectionner tout |
function Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL; stdcall;
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | Uses ShellApi, … ; … Procedure TForm1.AjouteIcone; Var Info:TNotifyIconData; begin { If faut tout d'abord remplir la structure Info} { avec ce que l'on veut faire} { cbSize doit contenir la taille de la structure} Info.cbSize := SizeOf(Info); { Wnd doit contenir le Handle de la fenêtre qui recevra les messages de} { notification d'évènement de la souris} Info.Wnd := Handle; { uID Numéro d'icone, c'est utile si plusieurs icones sont affichées en} { simultané dans la barre des tâches. Car c'est ce numéro qui permettra} { ensuite de modifier celle que l'on veut.} Info.uID := 1; { szTip contient le texte de l'info bulle affiché au dessus de l'icone} Info.szTip := 'Exemple d''icones par Nono40'; { hIcon contient le handle de l'icône qui doit être affichée} {Ici nous affichons l'icone de l'application} Info.hIcon := Application.Icon.Handle; { uCallBackMessage contient le message qui sera retourné à la fenêtre} { donnée par Wnd quand un évènement de souris apparaît sur l'icone} Info.uCallbackMessage := WM_MONICONE; { uFlags doit contenir la liste des champs utilisés dans la structure} { parmi les champs szTip,hIcon et uCallBackMessage} Info.uFlags := NIF_TIP Or NIF_ICON Or NIF_MESSAGE; { Appel de la fonction API ajoutant l'icone} Shell_NotifyIcon(NIM_ADD,@Info); End; |
Pour la suppression, il suffit juste d'indiquer le numéro de l'icone :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | Procedure TForm1.SupprimeIcone; Var Info:TNotifyIconData; begin { Dans le cas de la suppression d'une icone, seuls les champs ci-dessous} { sont nécessaires} Info.cbSize := SizeOf(Info); Info.Wnd := Handle; Info.uID := 1; Shell_NotifyIcon(NIM_DELETE,@Info); End; |
Il est possible aussi de gérer les messages lors de clics (gauche/droite/double) sur l'icône. La méthode est détaillée dans le code source joint.
Sans barre de titre, l'utilisateur ne peut déplacer simplement la fenêtre à l'aide de la souris. Il est cependant possible de simuler ce fonctionnement lors d'un click sur la surface de la fiche. Cette méthode doit être utilisée dans le cas d'un fiche ayant BorderStyle=bsNone.
Le code suivant doit être ajouté dans l'évènement OnMouseDown de la fiche :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 | procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ReleaseCapture; Perform(WM_SysCommand, SC_MOVE, 0); end; |
Une autre technique utilise le message WM_NCHITTEST envoyé par Windows à votre fenêtre lorsque l'utilisateur bouge la souris. La réponse à ce message est utilisée par Windows pour déterminer dans quelle zone se trouve la souris : dans la partie cliente, sur un bouton système, sur un des bords, etc.
Une de ces réponses nous intéresse particulièrement, il s'agit de la valeur HTCAPTION, qui indique à Windows que le curseur se trouve sur la barre de titre. Dans ce cas, Windows interprètera le déplacement de la souris avec le bouton gauche enfoncé comme un déplacement de la fenêtre. C'est exactement ce qu'il nous faut. Nous allons donc ajouter un gestionnaire de message pour WM_NCHITTEST à notre fenêtre et retourner la valeur HTCAPTION.
L'exemple suivant autorise le déplacement si le curseur se trouve dans la bande de 20 pixels de haut située en haut de la fenêtre, ce qui nous permet de simuler notre propre barre de titre :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | interface uses Windows, Messages, Classes, Forms; type TForm1 = class(TForm) private { Déclarations privées } public { Déclarations publiques } procedure WMNCHitTest(var msg: TWMNCHitTest); message WM_NCHITTEST; end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.WMNCHitTest(var msg: TWMNCHittest); var pt: TPoint; begin inherited; pt:= ScreenToClient(Point(msg.XPos, msg.YPos)); if PtInRect(Rect(0, 0, ClientWidth, 20), pt) then msg.Result:= HTCAPTION; end; |
En partant du même principe que pour le déplacement de la fenêtre, nous allons simuler la présence de bordures sur une fenêtre ayant sa propriété BorderStyle = bsNone. Le message WMHitTest se produit comme un MouseMouve et renvoie la position de la souris sur la fiche. Il suffit donc de choisir une zone, par exemple à droite de la fiche pour laquelle on enverra le message "La souris est sur la bordure droite, redimensionnement possible".
Déclaration :
Code delphi : | Sélectionner tout |
1 2 | {public} procedure WMNCHitTest(var msg: TWMNCHitTest); message WM_NCHITTEST; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | procedure TForm1.WMNCHitTest(var msg: TWMNCHittest); var pt: TPoint; begin // Stockage de la position de la souris pt := ScreenToClient(Point(msg.XPos, msg.YPos)); // On teste si la souris est sur l'un des cotés / ****Côté DROIT**** if PtInRect(Rect(ClientWidth-5, 0, ClientWidth, ClientHeight), pt) then begin msg.Result:= HTRIGHT; exit; end; end; |
Notes :
Pour recréer un redimensionnement classique il faut faire un test pour chaque coté et chaque coin de la fiche.
Attention à tester les coins avant les bords et à bien utiliser l'instruction Exit. (Sinon on se trouve dans un coin ET sur les bords)
Quelques résultats à utiliser :
- Bordure du bas : HTBOTTOM
- Bordure gauche : HTLEFT
- Bordure droite : HTRIGHT
- Bordure du haut : HTTOP
Toutes les constantes peuvent être trouvées à cette adresse : Hit Test Return Values
Dernier point : cette procédure ne fonctionne que quand la souris passe sur la fiche. Si vous avez par exemple une DBGrid avec align = alclient alors on ne passera pas dans notre WMNCHitTest.
La solution : créer des panels Enabled = False tout autour de la fiche (avec Align = AlLeft, AlRight etc.) de 2 ou 3 pixels de large.
Vous l'avez sans doute remarqué, Windows XP a introduit de nouvelles versions des contrôles graphiques habituels.
Si vous créez une application quelconque et que vous l'exécutez sous Windows XP vous vous rendrez compte que celle-ci n'utilise pas ces nouveaux contrôles. Pour quelle raison ? Tout simplement pas souci de compatibilité. Pour qu'une application utilise les contrôles XP, elle doit le signaler au système d'exploitation. La façon la plus simple de le faire sous Delphi 7 est d'ajouter un composant TXPManifest à n'importe quelle fenêtre du projet. Si vous avez la curiosité d'aller voir le code de ce composant, vous serez certainement surpris de voir que celui-ci ne fait strictement rien : il ne possède ni méthode ni propriété.
Alors comment cela peut-il fonctionner ? En y regardant de plus près, nous nous apercevons qu'il existe une ligne inhabituelle dans le code source de l'unité XPMan :
Code delphi : | Sélectionner tout |
{$R WindowsXP.res}
Ce fichier contient un fichier XML appelé manifeste XP. Celui-ci a la forme suivante :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="NomSociété.NomProduit.NomApplication" type="win32" /> <description>Un descriptif de votre application ici.</description> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" /> </dependentAssembly> </dependency> </assembly> |
L'incorporation de ce fichier aux ressources se fait par l'intermédiaire d'un fichier .rc qui une fois compilé vous donnera un fichier .res que vous pourrez recenser directement par la directive $R de Delphi.
Nous ne décrirons pas ici le processus complet de création de fichier ressource, mais sachez que le fichier .rc devra contenir une ligne de la forme :
Code other : | Sélectionner tout |
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "VotreFichierManifeste.xml"
Pour réduire toute les fenêtres il suffit de simuler l'appui simultanées de la touche Windows et de la touche M.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | procedure TForm1.BitBtn1Click(Sender: TObject); begin // Simule l'appui de la touche Windows Keybd_event(VK_LWIN,0,0,0); // Simule l'appui sur la touche M Keybd_event(VKKeyScan('m'),0,0,0); // Simule le relâchement de la touche Windows Keybd_event(VK_LWIN,0,KEYEVENTF_KEYUP,0); // Simule le relâchement de la touche M Keybd_event(VKKeyScan('m'),0,KEYEVENTF_KEYUP,0); end; |
Une autre méthode permet de réaliser cette fonction :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | uses ComObj;... var Shell : OleVariant; begin Shell := CreateOleObject('Shell.Application') ; // Minimise toutes les fenêtres Shell.MinimizeAll; // Maximise toutes les fenêtres Shell.UndoMinimizeAll; end; |
Pour notifier l'utilisateur que l'application attend quelque chose de sa part (confirmation d'un message, événement à valider, etc.) alors qu'elle n'a pas le focus, on peut faire clignoter une fenêtre en utilisant l'API FlashWindow. Le premier paramètre attendu est le handle de la fenêtre à flasher, le second un booléen indiquant si le clignotement doit être effectué ou la fenêtre doit revenir à son état initial.
Dans un timer dont la propriété Interval est réglée à 500ms, la ligne suivante dans OnTimer :
Code delphi : | Sélectionner tout |
FlashWindow(Form1.Handle,True);
On peut utiliser un objet encapsulant l'API :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | TFlasher = class private FTimer : TTimer; FHandle : Cardinal; procedure DoFlash(Sender : TObject); public procedure StartNotify; procedure EndNotify; constructor Create(ObjectToFlash : TWinControl; AInterval : Cardinal = 500); destructor Destroy; end; { TFlasher } procedure TFlasher.DoFlash(Sender : TObject); begin FlashWindow(FHandle,True); FlashWindow(Application.Handle,True); end; constructor TFlasher.Create(ObjectToFlash : TWinControl; AInterval: Cardinal); begin FTimer := TTimer.Create(nil); FTimer.Enabled := False; FTimer.Interval := AInterval; FTimer.OnTimer := DoFlash; FHandle := ObjectToFlash.Handle; end; destructor TFlasher.Destroy; begin FTimer.Free; end; procedure TFlasher.EndNotify; begin FTimer.Enabled := False; FlashWindow(FHandle,False); end; procedure TFlasher.StartNotify; begin FTimer.Enabled := True; DoFlash(nil); end; Function TFlasher.Actif:Boolean; begin Result:=FTimer.Enabled; end; |
On peut utiliser deux techniques "simples" :
lien MSDN : Architecture DCOM
DCOM permet d'instancier et d'exécuter une application (serveur automation) sur une machine distante à la condition que l'application ait été correctement enregistrée sur les 2 machines.
lien MSDN : Informations sur ORPC
RPC, ce protocole permet d'exécuter des commandes sur une machine distante mais nécessite que le client soit sous NT et que le service soit actif/démarré.
"Il existe de nombreux protocole RPC et Microsoft a choisi d'en adopter un plutôt que d'en créer un nouveau. Emprunté au DCE ( Distributing Computing Environment) de l'OSF (Open Software Fundation). Microsoft le nomme MS RPC ( En fait Microsoft n'a pas repris l'implémentation du protocole de l'OSF, mais à réimplémenté le RPC du DCE à partir des spécifications publiées).
Ce protocole ainsi que son adpatation DCOM connue sous le nom de RPC Objet (ORPC), envoie sur le réseau des informations de même format que le RPC du DCE (les mêmes structure de paquet)"
Extrait du livre Au coeur d'ActiveX et OLE de David Chapell chez MS-Press (c) 1996.
Il est possible d'associer une console à une application GUI pour, par exemple, y afficher des informations de debug… Dans ce cas, l'utilisation des directives de compilation prend tout son intérêt :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | {$IFDEF DEBUG} AllocConsole; WriteLn(DateTimeToStr(Now),': ',CmdLine); {$ENDIF} [...] {$IFDEF DEBUG} WriteLn('Entrée dans la procédure de sauvegarde'); {$ENDIF} |
- si on ferme la console, l'application est également fermée !!
- On ne peut pas associer plusieurs consoles à une seule et même application
Si on veut gérer les saisie dans cette fenêtre console, il faut utiliser un thread afin de ne pas bloquer le reste de l'application :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMonThread = class(TThread) AChar: Char; private procedure PutChar; public ConHan: THandle; procedure Execute; override; end; TForm1 = class(TForm) Memo1: TMemo; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Déclarations privées } public { Déclarations publiques } end; var Form1: TForm1; MonThread: TMonThread; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin AllocConsole; MonThread := TMonThread.Create(True); MonThread.FreeOnTerminate := True; MonThread.ConHan := GetStdHandle(STD_INPUT_HANDLE); ; MonThread.Resume; end; { TMonThread } procedure TMonThread.Execute; var Buffer: TInputRecord; Read: DWORD; begin inherited; while not Terminated do begin ReadConsoleInput(ConHan,Buffer,1,Read); if (Buffer.EventType = KEY_EVENT) and (Buffer.Event.KeyEvent.bKeyDown) then begin AChar := Buffer.Event.KeyEvent.AsciiChar; Synchronize(PutChar); end; end; end; procedure TMonThread.PutChar; begin Form1.Memo1.SelText := AChar; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin MonThread.Terminate; end; end. |
Parfois pour des raisons de simplification de déploiement d'une application, il peut être judicieux d'insérer un second exécutable dans son propre programme. Son extraction se faisant par celui-ci, on simule donc le principe d'une archive auto-extractible suivi d'une exécution de code.
L'idée est de créer un fichier de ressources contenant les données du fichier à inclure puis de déclarer, dans le fichier source du programme principal, une directive de compilation de type {$R nom.res}. Sa présence informe le compilateur d'ajouter le fichier de ressources nom.res à l'exécutable généré à la compilation.
Cette opération est similaire au principe d'une concaténation de fichiers via la commande :
Code other : | Sélectionner tout |
Copy /B Fichier1.exe+Fichier2.exe
Voici les étapes à suivre pour créer le fichier de ressources, l'inclure et l'extraire de l'exécutable :
- Dans le dossier qui contient le fichier à inclure, créez un nouveau document texte avec un éditeur ASCII.
- Dans ce document texte, saisissez la ligne :
Code other : Sélectionner tout NomDeRessource RCDATA NomDeExécutable
Pour le bloc-notes, nommé notepad.exe, inclus dans les distributions de Windows cela nous donne :
Code other : Sélectionner tout BlocNotes RCDATA "notepad.exe"
- Enregistrez ce fichier texte en le renommant en nom.rc. Ici le nom doit correspondre au nom indiqué dans la directive de compilation insérée dans le code source. Seule l'extension change, le fichier nom.res étant généré à partir de nom.rc.
- Ensuite dans une console (interface utilisateur en ligne de commande, cf. cmd.exe pour Windows NT et supérieur, command.com pour Windows 98), placez-vous dans le dossier hébergeant le fichier texte créé précédemment.
Exécutez la commande suivante :
Code other : Sélectionner tout brcc32 nom.rc
- Maintenant, dans l'unité principale de votre programme, insérez la directive de compilation "{$ nom.res}". Ainsi, lors de chaque compilation, la ressource (ici un fichier .exe) sera incluse avec votre programme principal.
- Désormais pour pouvoir utiliser cette ressource il faut créer deux stream : un TFileStream et un TResourceStream.
Créez le TResourceStream en lui passant en paramètres les informations nécessaires à l'ouverture de la ressource que vous avez incluses :
Code delphi : | Sélectionner tout |
MonResourceStream := TResourceStream.Create(hInstance, Nom, RT_RCDATA);
- hInstance est le numéro d'instance de votre application. Il sert au système pour retrouver en mémoire l'image de votre application et ainsi naviguer dans les entêtes afin de récupérer la ressource qui vous intéresse.
- Nom est une string contenant le nom de la ressource que vous souhaitez extraire. Si l'on reprend l'exemple plus haut, on a Nom = 'BlocNotes'
- RT_RCDATA indique le type de la ressource, comme vous l'avez spécifié dans votre fichier nom.rc.
Ensuite créez le TFileStream en mode création de fichier (option fmCreate) en lui donnant le nom de fichier que vous voulez, et exécutez l'instruction :
Code delphi : | Sélectionner tout |
MonFileStream.CopyFrom(MonResourceStream, 0);
Pour plus de détails sur l'utilisation des ressources avec votre application, référez-vous à cet article de DelphiCool.
Il existe un composant shareware, TRCData, qui permet cette opération en mode conception.
Tout d'abord, mettre la propriété KeyPreview de la fiche à True.
Ensuite, il est possible d'implémenter les gestionnaires d'évènements suivants :
- OnKeyDown / OnKeyUp : pour voir toutes les touches (y compris étendues), et même les clics souris.
- OnKeyPress : Pour les touches simples, y compris la touche ESC.
Exemple d'un gestionnaire OnKeyPress permettant de fermer la fiche sur appui de la touche ESC :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin // Un appui sur ESC émet un caractère #27. If (Key=Char(VK_ESCAPE)) Then Close ; end; |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin // On ne veut pas autre chose que ces 2 touches. If Shift=[ssCtrl,ssAlt] Then // Pour les caractères alphanumériques, utiliser la fonction Ord // pour le test du code. If Key=Ord('M') Then Close ; end; |
Il est parfois difficile de compresser un exécutable Win32 de manière efficace. Il est encore plus pénible de devoir compresser manuellement ses ressources pour réduire la taille de l'exécutable.
Une solution peut être d'utiliser UPX : ce compresseur est freeware, ses sources sont disponibles si besoin, et il peut compresser un exécutable tout en le laissant exécutable.
Une ligne de commande simple et efficace est :
Code other : | Sélectionner tout |
upx -9 --best -v MonProgramme.exe
La réalisation de ce genre de programme dépasse le cadre de cette FAQ mais vous pouvez utiliser ou vous inspirer des articles et programmes disponibles aux adresses suivantes :
Introduction à DirectX 9 en Delphi, par Pierre Castelain
Effet Matrix
Pour n'avoir qu'une instance d'une fenêtre fille dans notre application, il faut, avant de créer une nouvelle instance,s'assurer qu'il n'y en a pas déjà une. Pour le faire, nous pouvons parcourir le tableau contenant les références vers les fenêtres filles existantes comme cela est montré dans le code ci-dessus (code issu du projet exemple AppMDI) :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | procedure TMainForm.CreateMDIChild(const Name: string); var Child: TMDIChild; //<- TMDIChild est la classe de la fenêtre fille Nbr : Integer; i : Integer; begin Nbr:=0; //On parcourt le tableau des fenêtres filles For i:= 0 To MDIChildCount-1 Do If MDIChildren[i] is TMDIChild Then Inc(nbr); { crée une nouvelle fenêtre MDI enfant } If Nbr<2 Then Begin Child := TMDIChild.Create(Application); Child.Caption := Name; //Traitement.... End; end; |
Une ressource consiste en un fichier binaire, typiquement d'extension .res, qui est inclus à la compilation dans votre EXE final.
Afin de générer ce fichier de ressources, il faut utiliser un compilateur de ressources, qui prend en entrée un fichier texte (d'extension .rc) de définition indiquant au compilateur quels données/fichiers compiler.
La syntaxe (minimale) d'un tel fichier est la suivante :
Code other : | Sélectionner tout |
IDRessource TYPE DonnéeOuCheminDeFichier
- IDRessource est un nom unique ou un entier non signé de 16 bits (de 0 à 65535) qui servira à identifier votre ressource au sein des autres ressources de votre exécutable.
- TYPE représente le type de ressource que vous souhaitez inclure. Les possibilités sont multiples : BITMAP, ICON, CURSOR, RCDATA... Ce dernier type vous permet par exemple d'inclure le fichier de votre choix en ressource. Référez vous à la librairie MSDN pour la liste exhaustive des types de ressources disponibles.
- DonnéeOuCheminDeFichier est la donnée à compiler dans le fichier de ressources. Pour un type BITMAP ou ICON il s'agit du chemin complet entre guillemets de l'image à inclure (ou simplement le nom du fichier s'il se trouve dans le même répertoire que le fichier .rc). Pour le type RCDATA cela peut être un fichier, une chaîne de caractères, un nombre etc. Référez-vous à la librairie MSDN pour plus d'informations.
Voici un exemple de fichier .rc :
Code other : | Sélectionner tout |
1 2 3 | FichierQuelconque RCDATA MonFichier.xyz SplashScreen BITMAP splash.bmp UneIcone ICON icone.ico |
En ligne de commande, placez-vous dans le répertoire de votre fichier .rc et exécutez :
Code other : | Sélectionner tout |
brcc32 fichier.rc
Pour ce faire, éditez le fichier .dpr de votre projet et ajoutez-y cette directive de compilation en vous assurant que FichierDeRessource.res se trouve dans le répertoire de votre projet :
Code delphi : | Sélectionner tout |
{$R FichierDeRessources.res}
Lien MSDN : RCDATA Resource
Utilisez les ressources dans votre application Delphi, par DelphiCool
Il est possible de le faire de deux façons différentes.
La première méthode renomme directement les variables.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | uses Consts; procedure ChangeResourceString(ResString: PResStringRec;NewText:string); var I: Integer; OldProtect, Rien: DWORD; begin //On change les autorisations d'accès à notre variable //(Restring est un pointeur sur notre chaîne de resource) //qui est censée être en lecture seule (notre pointeur sur la chaîne de //resources est une constante) Win32Check(VirtualProtect(ResString, SizeOf(TResStringRec),PAGE_READWRITE, OldProtect)); //maintenant, le pointeur sur la chaîne de resources est devenu une variable try //On change le pointeur sur la chaîne de resources pour qu'il pointe //sur notre texte ResString^.Identifier:=Integer(PChar(NewText)); finally //Pour être cohérent avec Windows, on retransforme notre "variable" en "constante" VirtualProtect(ResString, SizeOf(TResStringRec), OldProtect,Rien); end; end; |
Exemple d'appel :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | procedure TForm1.Button1Click(Sender: TObject); begin ChangeResourceString(@SMsgDlgYes,'Peut-être'); ChangeResourceString(@SMsgDlgNo,'Bof'); ChangeResourceString(@SMsgDlgIgnore,'Ca dépend'); MessageDlg('Ma boite de dialogue', mtWarning, [mbYes,mbNo,mbIgnore], 0); end; |
L'autre méthode consiste à créer la boîte de dialogue à l'aide de CreateMessageDialog et à modifier la propriété Caption du bouton :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var i: integer; FicheMessage: TForm; begin // on crée la fiche de dialogue à la main FicheMessage := CreateMessageDialog('Ma boite de dialogue', mtWarning, [mbYes, mbNo, mbIgnore]); // pour chaque bouton de la fiche ainsi crée on change (si on le souhaite) son modalresult et son caption for i := 0 to FicheMessage.ComponentCount - 1 do if ( FicheMessage.Components[i] is TButton ) then with ( FicheMessage.Components[i] as Tbutton ) do begin //on change ici selon son humeur, la valeur déjà présente dans Caption, etc.. //Caption := ... ; //ModalResult := ...; If Caption=SMsgDlgYes then Caption:='Ouais !'; end; //On montre la boite de dialogue FicheMessage.ShowModal; FicheMessage.Release; //on libère la mémoire occupée par la fiche end; |
Il existe deux méthodes assez simples pour enlever la croix de fermeture des fenêtres tout en gardant les autres boutons (réduire, maximiser, etc.).
Toutes les fonctions et types de variables déclarés ci-dessous sont implémentés dans l'unité Windows.
Première méthode :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | var HD:HMENU; begin HD:=GetSystemMenu(HANDLE,false); // On récupère le menu système // On enlève le menu associé à SC_CLOSE if (HD<>null)then RemoveMenu(HD, SC_CLOSE,0); SetWindowPos(HANDLE,0,0,0,0,0,swp_nosize or swp_nomove or swp_nozorder or swp_drawframe); end; |
Cette seconde méthode remplace SetWindowPos par DrawMenuBar qui permet de redessiner la barre de menus :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 | var HD:HMENU; begin HD := GetSystemMenu(HANDLE, false); if (HD<>null) then RemoveMenu(HD, SC_CLOSE, 0); DrawMenuBar(HANDLE); //Redessine la barre de menus end; |
Vous trouverez ici quelques liens concernant la création de fichiers d'aide .HLP ou .CHM :
Tutoriels Delphi Fichier d'aide
Tutoriel VB : Créer un fichier d'aide de type .chm (format html)
Outils de génération de documentation : Documentation
FAQ VC++ et MFC : IDE, Environnement de développement
Un site complet sur les différents systèmes d'aide : http://www.helpwaregroup.com/
Vous y trouverez par exemple un outil permettant d'utiliser la documentation de Delphi 2005 en dehors de l'IDE :
http://www.helpware.net/mshelp2/dexplore/dexplorer.htm
Pour cela, il suffit d'utiliser la méthode TApplication.ProcessMessages et la fonction GetTickCount pour contrôler le temps de pause.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | procedure Pause(const nDuree: Cardinal); var Tc: Cardinal; begin Tc := GetTickCount; // Récupère le nombre de Ticks (de millisecondes) repeat Application.ProcessMessages;//Traite les messages Sleep(1); // Le Sleep sert ici uniquement à délester le CPU // Plus la valeur sera faible, plus le processus sera prioritaire until Cardinal(GetTickCount - Tc) > nDuree; end; |
Nous nous proposons ici de créer une boite de dialogue en y intégrant un ou plusieurs contrôles (visuels ou non).
Nous verrons aussi comment les contrôles créés peuvent répondre à des évènements (lien internet, fermeture automatique grace à un Timer)
Le principe :
- Nous créons une boite de dialogue en utilisant CreateMessageDialog
- Cette fonction renvoie un objet fiche de type TForm.
- Dans cette fiche, tout comme dans n'importe quelle fiche, nous pouvons y créer dynamiquement un contrôle (on peut même déplacer les contrôles qui s'y trouvent déjà comme les boutons), en prenant soin de renseigner les propriétés Owner (lors du Create), Parent et Name.
- Nous appelons notre boite de dialogue avec sa méthode ShowModal.
- Nous détruisons la boite de dialogue avec sa méthode Free.
Si nous souhaitons utiliser un évènement de ce contrôle (OnClick, OnTimer, etc.) :
- Nous codons l'évènement dans la fiche qui appelle la boite de dialoque
Si nous souhaitons mettre à jour le contenu de ce contrôle suite à l'évènement codé :
- Nous recherchons depuis le code de l'évènement le contrôle à mettre à jour grace à son nom que nous aurons préalablement pris soin de renseigner.
Nous allons tenter de couvrir tous ces aspects en 4 exemples, en partant du plus simple, au plus élaboré.
Exemple 1 : afficher un Logo commercial, une image de fond, etc.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var AMsgDialog : TForm; UneImage : TImage; begin AMsgDialog := CreateMessageDialog('Le message', mtWarning, [mbYes, mbNo]) ; UneImage := TImage.Create(AMsgDialog); try AMsgDialog.Caption := 'Un exemple de logo'; with UneImage do begin Name := 'MonImage'; Parent := AMsgDialog; // Ligne importante : si absente, le contrôle ne s'affichera pas Align:=alclient; SendToBack; // Placer l'image en arrière plan Picture.LoadFromFile('MonLogo.bmp'); end; AMsgDialog.ShowModal; finally // Libération de la boite de dialogue AMsgDialog.Free; end; end; |
Il est possible de redimensionner la boite de dialogue, changer sa hauteur par exemple, afin de placer des composants sous les boutons.
Dans le projet suivant, nous avons placé un TButton sur une fiche vierge
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Déclarations privées } procedure LabelClick(Sender: TObject) ; public { Déclarations publiques } end; var Form1: TForm1; implementation uses ComCtrls,ExtCtrls,ShellApi; {$R *.dfm} // Code de l'évènement OnClick du Label procedure TForm1.LabelClick(Sender: TObject); begin ShellExecute(Handle, 'OPEN', 'http://www.Developpez.com', Nil, Nil, SW_SHOW); end; // Bouton qui affiche la boite de dialogue procedure TForm1.Button1Click(Sender: TObject); var AMsgDialog : TForm; UnLabel : TLabel; begin AMsgDialog := CreateMessageDialog('Le message', mtWarning, [mbYes, mbNo]) ; UnLabel := TLabel.Create(AMsgDialog); try AMsgDialog.Caption := 'Evènement utilisateur'; // On peut redimmensionner la boite de dialogue comme ceci : AMsgDialog.Height := AMsgDialog.Height+15; with UnLabel do begin Name := 'MonLien'; Parent := AMsgDialog; Align:=albottom; Alignment:=taCenter; // Imitation d'un lien internet Caption := 'http://www.Developpez.com'; Cursor := crHandPoint; Font.Style := [fsUnderline]; Font.Color := clBlue; // On relie l'évènement OnClick du Label à la procédure LabelClick de notre fiche appelante UnLabel.OnClick:=LabelClick; end; // Affichage de la boite de dialogue AMsgDialog.ShowModal; finally // On détache la procédure de l'évènement UnLabel.OnClick:=nil; // Libération de la boite de dialogue AMsgDialog.Free; end; end; end. |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Déclarations privées } procedure DlgTimer(Sender: TObject); public { Déclarations publiques } end; var Form1: TForm1; implementation uses ComCtrls,ExtCtrls,ShellApi; {$R *.dfm} // Code de l'évènement OnClick du Label procedure TForm1.DlgTimer(Sender: TObject); begin if ((Sender as TTimer).Owner) is TForm then with ((Sender as TTimer).Owner) as TForm do ModalResult := mrCancel; // Provoque la fermeture de la boite de dialogue end; // Bouton qui affiche la boite de dialogue procedure TForm1.Button1Click(Sender: TObject); var AMsgDialog : TForm; ATimer : TTimer; begin AMsgDialog := CreateMessageDialog('Fermeture automatique dans 5 secondes', mtInformation, []) ; ATimer := TTimer.Create(AMsgDialog); try AMsgDialog.Caption := 'Fermeture automatique'; AMsgDialog.Cursor:=crHourGlass; with ATimer do begin Interval := 5000; //5 secondes //On relie l'évènement OnTimer à la procédure DlgTimer de notre fiche appelante ATimer.OnTimer:=DlgTimer; end; //Affichage de la boite de dialogue AMsgDialog.ShowModal; finally //Libération de la boite de dialogue ATimer.OnTimer:=nil; AMsgDialog.Free; end; end; end. |
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Déclarations privées } procedure DlgTimer(Sender: TObject) ; public { Déclarations publiques } end; var Form1: TForm1; implementation uses ComCtrls,ExtCtrls,ShellApi,DateUtils; {$R *.dfm} procedure TForm1.DlgTimer(Sender: TObject); var UnLabel:TLabel; begin if ((Sender as TTimer).Owner) is TForm then with ((Sender as TTimer).Owner) as TForm do begin //Recherche du Label sur la boite de dialogue UnLabel:=TLabel(FindComponent('MonHorloge')); UnLabel.Caption:=FormatDateTime('dddd d mmmm yyyy, h"h"mm"mn"ss"s"',Now); end; end; procedure TForm1.Button1Click(Sender: TObject); var AMsgDialog : TForm; ATimer : TTimer; ALabel:TLabel; begin AMsgDialog := CreateMessageDialog('', mtInformation, [mbOK]) ; ATimer := TTimer.Create(AMsgDialog); ALabel:=TLabel.Create(AMsgDialog); try AMsgDialog.Caption := 'Exemple de mise à jour d''un contrôle'; //On agrandit la fiche AMsgDialog.Width:=300; with ALabel do begin Name:='MonHorloge'; Parent:=AMsgDialog; Left:=50; Top:=5; end; with ATimer do begin Interval := 1000; //Déclenchement du timer chaque seconde //On relie l'évènement OnTimer à la procédure DlgTimer de notre fiche appelante ATimer.OnTimer:=DlgTimer; end; //Affichage de la boite de dialogue AMsgDialog.ShowModal; finally //Libération de la boite de dialogue ATimer.OnTimer:=nil; AMsgDialog.Free; end; end; end. |
Il faut savoir que le fichier INI n'est rien d'autre qu'un fichier texte avec une structure définie. Du coup, remplacer une section revient à charger le fichier comme n'importe quel autre fichier texte, rechercher la position de la section dans le fichier, puis la remplacer par la nouvelle.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function RenommerSection(NomFichier,AncienNom,NouveauNom:string):boolean; var i:integer; AStringList:TStringList; begin Result:=false; AStringList:=TStringList.Create; try AStringList.LoadFromFile(Fichier); i:=AStringList.IndexOf('['+AncienNom+']'); if i>-1 then begin AStringList.Strings[i]:='['+NouveauNom+']'; AStringList.SaveToFile(NomFichier); Result:=True; end; finally AStringList.Free; end; end; |
Code delphi : | Sélectionner tout |
1 2 3 4 | if RenommerSection('MonFichier.ini','Section1','SectionA') then Showmessage('Section renommée avec succès !') else Showmessage('Ca n''a pas marché...'); |
Width définit la largeur absolue, entière de l'application dont les bordures.
Height, la hauteur absolue de l'application dont les bordures, le TMainMenu, et la barre de titre (boutons Fermer l'application, Réduire...)
ClientWidth et ClientHeight sont la largeur / la hauteur intérieure de la fenêtre sans bordures ou menu. C'est la surface dans laquelle vous pouvez placer vos contrôles.
Quand on compile une application avec les versions récentes de Delphi (Delphi 10.3 par exemple), elle hérite automatiquement du style Windows 10.
Par contre, avec Delphi 7, même sous Windows10, une application conserve le style ancien de Windows XP (Contrôles Windows d'apparence 3D)
Pour donner le style Windows 10 à une application compilée avec Delphi 7, il suffit d'ajouter au projet un ficher Manifest (*.Manisfest) sous forme d'un fichier ressource (*.Res).
Dans les versions récentes de Delphi le fichier ressource standard peut être modifié et intégré dans le projet directement dans l'application depuis l'IDE. Pour cela :
- Aller dans Projet > Options > Application > Manifeste ;
- Choisir la plate-forme cible ;
- Sélectionner "Générer automatiquement" dans la liste déroulante ;
- Cliquer sur "Enregistrer".
Avec Delphi 7, il faut créer un fichier manifest, un fichier RC et compiler ce fichier avec Brcc32.exe, pour obtenir le fichier Res, à inclure dans le code du projet.
Le fichier manifest est un fichier au format XML et donc modifiable sous Notepad par exemple.
Ce fichier d'extension .manifest, permet :
- De donner au contrôles de Windows l'aspect de la version de l'os utilisé (dont Windows 10) ;
- De fixer le niveau d'élévation de privilège de l'application (spécifie par exemple si l'application a besoin de s'exécuter avec des privilèges administrateur) ;
- De permettre la prise en charge ou non des écrans à très haute résolution (au delà du Full HD : 1920 x 1080 pixels).
Pour donner l'aspect Windows 10 à votre application, créer le fichier Win10Theme.manifest suivant :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity type="win32" name="App" version="3.1.0.0" processorArchitecture="*"/> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" publicKeyToken="6595b64144ccf1df" language="*" processorArchitecture="*"/> </dependentAssembly> </dependency> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!--The ID below indicates application support for Windows Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> <!--The ID below indicates application support for Windows 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> <!--The ID below indicates application support for Windows 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> <!--The ID below indicates application support for Windows 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <!--The ID below indicates application support for Windows 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> </application> </compatibility></assembly> |
Créer ensuite, dans le même répertoire, le fichier Win10Theme.rc suivant :
Code text : | Sélectionner tout |
1 24 Win10Theme.manifest
Code shell : | Sélectionner tout |
1 2 | "$Delphi7\Bin\brcc32.exe" "$MonRep\Win10Theme.rc" Pause |
Exécuter Win10Theme.cmd. Le fichier Win10Theme.RES est créé dans le répertoire $MonRep. Le recopier dans le répertoire de votre application.
Dans le code de la fenêtre de votre application, dans la section Implementation, après {$R *.dfm}, insérer la ligne :
Code : | Sélectionner tout |
{$R 'Win10Theme.res'}
En développant avec Delphi 7 sous Windows 11, les applications possèdent le style WindowsXP. Il est toutefois possible de leur donner le style des fenêtres et contrôles de Windows11.
Pour cela, il faut créer un fichier ressource par exemple W11.res.
Sous Notepad, créez le fichier W11.Manifest :
Code xml : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity type="win32" name="MyOrganization.MyDivision.MySampleApp" version="6.0.0.0" processorArchitecture="*" /> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" /> </dependentAssembly> </dependency> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <application> <!-- Windows 10 and Windows 11 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" /> <!-- Windows 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" /> <!-- Windows 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" /> <!-- Windows 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" /> <!-- Windows Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" /> </application> </compatibility> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"/> </requestedPrivileges> </security> </trustInfo> </assembly> |
Toujours avec Notepad, créez un second fichier nommé W11.rc :
Code shell : | Sélectionner tout |
1 2 | brcc32 W11.rc Pause |
Vous obtiendrez un fichier de ressource nommé W11.RES .
Ouvrez votre projet sous Delphi 7 et ajoutez une ligne après Program dans le fichier dpr :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | Program {$R 'W11.RES' 'W11.rc' } // ajouter cette ligne ici dans le dpr du projet Uses Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} ... |
Compilez puis exécutez pour avoir le style W11.
Seul inconvénient : l'appui sur les touches Alt ou Ctrl+Alt provoquent l'effacement de certains contrôles comme les boutons, cases à cocher ou boutons radio. Pour éviter cela, il faut neutraliser l'appui sur ces touches pour toute l'application. Pour cela, on intercepte les messages Windows grace à onMessage de TApplication :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | TForm1 = class(TForm) ... private procedure MessagesAppli(var Msg: TMsg; var Handled: Boolean); ... implementation {$R *.dfm} { ===========================================================================} procedure TForm1.FormCreate(Sender: TObject); begin Application.OnMessage := MessagesAppli; end; { ===========================================================================} procedure TForm1.MessagesAppli(var Msg: TMsg; var Handled: Boolean); // On utilise les codes virtuels de l'IME par exemple // pour pouvoir récupérer les touches Ctrl et Alt dans le onKeyDown begin if (Msg.message = WM_KEYDOWN) Then // Pour neutraliser Ctrl + Alt if GetAsyncKeyState(VK_Control) < 0 then Begin Msg.message := WM_SYSKEYDOWN ; Msg.wParam := VK_KANA ; End ; if Msg.message = WM_SYSKEYDOWN then // Pour Neutraliser Alt begin If Msg.wParam <> VK_KANA Then Msg.wParam := VK_JUNJA Else Msg.wParam := VK_HANJA ; end; end; |
On peut quand même utiliser les touches Ctrl et Alt, grace à la fonction OnKeyDown :
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin Caption := '' ; If Key = VK_JUNJA Then Caption := 'Alt a été appuyé' ; If Key = VK_HANJA Then Caption := 'Ctrl + Alt ont été appuyés' ; If Shift = [ssCtrl] Then Caption := 'Ctrl a été appuyé' ; // et aussi les autres touches ... end; |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.