FAQ DelphiConsultez toutes les FAQ

Nombre d'auteurs : 119, nombre de questions : 909, dernière mise à jour : 22 décembre 2016  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.

Commentez


SommaireInterface utilisateurApplication (30)
précédent sommaire suivant
 

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;

Mis à jour le 22 janvier 2014 Al-Yazdi

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;
Une solution simple serait de mettre au fond de la fenêtre un TImage aligné alClient et d'y affecter une image lors de sa création. Mais pourquoi superposer un dessin sur un dessin ? En effet, le fond de la fenêtre est lui aussi un dessin, mais par défaut, c'est un simple cadre à la couleur clBtnFace[Couleur de fond de fenêtre Windows]. Donc, l'idée, est de remplacer ce dessin par le dessin d'une image. On oublie donc le TImage, et on met un petit peu les mains dans le cambouis.

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.
Dans ce code, la form ne peut pas être créée automatiquement au lancement de l'application [par Application.CreateForm ], et cela impose de la créer manuellement. Voici le code d'un bouton de la fenêtre principale. Il affiche une boîte d'ouverture d'image, et crée une fiche MDI.
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;

Mis à jour le 22 janvier 2014 MD Software

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;
Il faut, pour que cela fonctionne, que vous spécifiez l'option Inclure les informations de version dans le projet dans menu Projet|Option|Information de version, ainsi la fonction retournera '1.0.0.0' par exemple, sinon la fonction déclenchera une erreur EAccessViolation.

Mis à jour le 13 octobre 2013 Gysmo

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
vous permettra de manipuler les écrans en tant que descendants du même ancêtre.

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;
Enfin, à la sortie de l'application, le frame actif ayant été créé dynamiquement, il est détruit manuellement :
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é.

Mis à jour le 13 octobre 2013 DidiLogic

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);
Ces deux fonctions créent une région elliptique dont les paramètres sont ceux de base pour créer une ellipse : un rectangle englobant dont les coordonnées sont données par rapport à la fiche.
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);
Où :
  • 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
Où :
  • 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;

Mis à jour le 13 octobre 2013 Al-Yazdi

À 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;

Mis à jour le 13 octobre 2013 Bloon

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;

Mis à jour le 13 octobre 2013 Nono40

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.
Ceci masque également l'application dans la barre des tâches et dans Alt-Tab tant qu'aucune autre fenêtre n'est affichée.

Mis à jour le 13 octobre 2013 Nono40

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);
Notez que pour rendre de nouveau l'application visible, il faut faire :
Code delphi : Sélectionner tout
ShowWindow(Application.Handle, SW_SHOW);

Mis à jour le 22 janvier 2014 Nono40

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;
Cette fonction permet d'ajouter, de modifier ou de supprimer une icône de la barre des tâches. Cette fonction prend en paramètre un enregistrement de description de l'icône. Pour créer une nouvelle icône, il convient de remplir convenablement cet enregistrement :
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.

Mis à jour le 13 octobre 2013 Bestiol Nono40

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;
Cette méthode peut aussi être appliquée à tous les descendants de TWinControl.

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;

Mis à jour le 13 octobre 2013 Nono40

Lien MSDN : WM_SYSCOMMAND message

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;
Implementation (extrait) :
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;
Ce code permet donc le redimensionnement du côté droit de notre fiche quand la souris est à 5 pixels du bord.

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.

Mis à jour le 22 janvier 2014 Manopower

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}
Cette ligne sert à ajouter le fichier WindowsXP.res aux ressources de l'application. Car c'est de cette façon que l'on signale à Windows XP que l'application doit utiliser les nouveaux contrôles. Cela permet au programme de fonctionner normalement sur les versions plus anciennes du système puisque seul Windows XP vérifie la présence de ce fichier particulier en ressources.
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>
Vous pouvez modifier les parties du fichier en français pour l'adapter à votre application.
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"
Le même processus pourra être utilisé pour une application du panneau de configuration ou une dll devant être chargé par RunDLL32 comme vous pourrez le lire dans l'article ci-dessous.

Mis à jour le 22 janvier 2014 Pierre Castelain

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;
La procédure Keybd_event est déclarée dans l'unité Windows sous D5.
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;

Mis à jour le 22 janvier 2014 Laurent Dardenne

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);
…fait clignoter en boucle la fenêtre "Form1" de l'application.

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;
Après l'avoir crée, on démarrera la processus de notification en appelant la méthode StartNotify et on arrêtera avec EndNotify.

Mis à jour le 22 janvier 2014 Reisubar

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.

Mis à jour le 22 janvier 2014 Laurent Dardenne

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}
Notes :
  • 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.

Mis à jour le 22 janvier 2014 Smortex

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
Bien qu'ici la difficulté est de savoir où se termine Fichier1.exe et où commence Fichier2.exe, et ce afin de bien distinguer les deux fichiers, Delphi nous permet de résoudre ce problème.
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
    Exemple :
    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
    Le programme brcc32.exe est en fait le compilateur de ressources fourni avec Delphi. Une fois ce fichier de ressources créé, déplacez-le, si besoin est, dans le même répertoire hébergeant les sources de votre programme principal.
  • 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);
Cette opération extrait le fichier inclus en ressources dans le répertoire désiré, vous pouvez dès lors l'utiliser.
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.

Mis à jour le 22 janvier 2014 Bestiol

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;
Ce gestionnaire réduit la fenêtre si l'on appuie sur Ctrl+Alt+M :
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;
Pour les touches étendues (F1, F2, etc...), des constantes sont définies dans l'unité Windows.pas, qui commençent toutes par " VK_ ". Par exemple, le code pour la touche F1 est VK_F1. L'aide Delphi recense tous ces codes dans la section "Codes de touches virtuelles", accessible notamment depuis l'aide des évènements OnKeyDown et OnKeyUp.

Mis à jour le 22 janvier 2014 Mac LAK

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
Il existe bien d'autres options de compression pour UPX, permettant d'avoir un meilleur taux de compression, mais celles-ci fonctionnent en général plutôt bien.

Mis à jour le 22 janvier 2014 Mac LAK

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 :

Mis à jour le 22 janvier 2014 Pierre Castelain

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;

Mis à jour le 22 janvier 2014 Nono40

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
Ces trois ressources seront incluses dans le même fichier de ressources. Pour générer ce fichier, vous pouvez utiliser le compilateur brcc32 fourni avec Delphi.
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
Cela vous génèrera le fichier .res, qu'il vous reste alors à inclure à votre projet Delphi.
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}
Il ne vous reste plus qu'à recompiler : les données de FichierDeRessource.res seront incluses dans votre EXE.

Mis à jour le 22 janvier 2014 Bestiol

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;

Mis à jour le 22 janvier 2014 LadyWasky Pedro

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;
Seconde méthode :

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;
Note : ces méthodes permettent d'enlever aussi les autres boutons en remplaçant SC_CLOSE par SC_MINIMIZE, SC_MAXIMIZE, SC_SIZE ou SC_MOVE.

Mis à jour le 22 janvier 2014 LadyWasky sofiane44

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

Mis à jour le 24 janvier 2014 Giovanny Temgoua Laurent Dardenne

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;

Mis à jour le 22 janvier 2014 Dry Lung

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;
Exemple 2 : Placer un Label, lien vers un site web
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.
Exemple 3 : Fermeture automatique d'un MessageDlg sans 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
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.
Exemple 4 : Afficher l'heure dans le MessageDlg
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.

Mis à jour le 22 janvier 2014 LadyWasky

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;
Exemple d'utilisation :
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é...');
Il est à noter qu'il est aussi possible de supprimer la section en utilisant la méthode EraseSection de TIniFile. Il suffit alors de recréer la section avec le nouveau nom et de rétablir les clés que contenait cette section.

Mis à jour le 22 janvier 2014 LadyWasky

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.

Mis à jour le 22 octobre 2015 Martin Lestas

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 ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les 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 © 2017 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.

 
Responsables bénévoles de la rubrique Delphi : Gilles Vasseur - Alcatîz -