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 fermer un menu Popup ?
- Comment Effacer le texte d'un TEdit avec le style clearingeditstyle ?
- Obtenir le nombre de pixels par pouce
- Comment ouvrir une forme sur la forme parente et centrer ?
- Comment parcourir les éléments d'un TTreeview
- Comment faire pour n'avoir qu'un seul élément sélectionné dans un TListView ?
- Comment trier un TListBox
- Comment modifier la couleur d'un panel ?
- Comment aligner les entêtes de colonnes d'une grille ?
- Comment changer l'alignement du contenu d'une colonne ?
Sous FMX un menu popup prend la main comme une fenêtre modale.
La forme appelante n'a donc pas d'accès direct pour fermer ce menu (en VCL on utilisait ClosePopup).
Pour fermer les popups d'une forme FMXForm1, on utilisera l'objet Screen (variable globale) et les instructions suivantes :
Code : | Sélectionner tout |
1 2 | Screen.PrepareClosePopups(FMXForm1); Screen.ClosePopupForms; |
- Les formes et modules de données créés par l'application.
- La forme active et le contrôle actif au sein de cette dernière.
- Le nombre de formes de cette application.
- Une liste des écrans sur lesquels les formes de l'application peuvent apparaitre ainsi que leurs coordonnées et dimensions.
Le style clearingeditstyle d'un TEdit permet d'ajouter un bouton contenant une croix dans la zone de saisie ; ce bouton permet à l'utilisateur d'effacer le texte en cliquant dessus.
Mais jusqu'à la version XE8, si l'on établit la propriété style d'un TEdit à clearingeditstyle (par l'inspecteur d'objets), le bouton apparaît bien dans la zone de saisie mais rien ne se passe lorsque l'utilisateur clique sur ce bouton (le texte n'est pas effacé).
Il y a quand même un moyen pour que cela fonctionne : (sur la fiche en conception) il faut pour cela faire bouton droit sur le TEdit et choisir 'Ajouter un élément' -> TClearEditButton. Cela rajoute le bouton dans la zone de saisie mais cette fois-ci, le clic sur ce bouton fonctionne, le texte est bien effacé.
Pour obtenir le nombre de pixels par pouce de l'écran en VCL, nous pouvons utiliser Screen.PixelsPerInch.
Avec FMX, c'est un peu plus complexe, car il faudra utiliser une interface particulière : IFMXDeviceMetricsService.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | function Pixels : integer; var D : IFMXDeviceMetricsService; Q : TDeviceDisplayMetrics; begin result:=96; // valeur par défaut windows if TPlatformServices.Current.SupportsPlatformService(IFMXDeviceMetricsService,D) then begin Q:=D.GetDisplayMetrics; result:=Q.PixelsPerInch; end; end; |
Aller dans l'Inspecteur d'objets, sélectionner la forme principale, puis Propriétés, Position et, dans la liste, choisir OwnerFormCenter. Faire de même pour la forme enfant.
La version TreeView du framework FMX ne propose pas les mêmes méthodes et propriétés que celui de la VCL.
Il y a trois possibilités pour parcourir l'arbre dépendant de l'objectif souhaité.
Parcourir les éléments de la racine
Pour cela il faut utiliser la propriété Count et la méthode IndexByIndex() du composant
* même les éléments cachés (propriétés visible:=false)
exemple :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | procedure TForm1.RacinesVisibles; var I: Integer; begin Memo1.lines.clear; for I := 0 to Arbre.count - 1 do begin // exemple de traitement // if arbre.ItemByIndex(i).Isselected then Memo1.lines.Add(Arbre.ItemByIndex(I).Text); end; end; |
Parcourir tous les éléments visibles* de l'arbre
Il faudra utiliser la propriété GlobalCount et la méthode ItemByGlobalIndex() du composant.
* Ici visible indique les éléments qui seront en vue (même ceux avec la propriété visible à false)
exemple :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | procedure TForm1.ElementsVisibles; var I: Integer; begin Memo1.lines.clear; for I := 0 to Arbre.GlobalCount - 1 do begin // exemple de traitement // if arbre.ItemByGlobalIndex(i).Isselected then Memo1.lines.Add(Arbre.ItemByGlobalIndex(I).Text); end; end; |
Parcourir tous les éléments de l'arbre
Pas de secret, il faudra passer par la récursivité et par la connaissance des propriétés des éléments d'un TreeView de type TTreeViewItem.
exemple :
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 | procedure TForm1.ArbreEntier; var I: Integer; // tous, selections, vue, visibles : Integer; procedure getChilds(AnItem: TTreeViewItem); var c: Integer; begin // if AnItem.isExpanded then inc(vus, AnItem.count); for c := 0 to AnItem.count - 1 do begin // inc(tous); // if AnItem.ItemByIndex(c).Isselected then inc(selections); // if AnItem.ItemByIndex(c).IsVisible then inc(visibles); Memo1.lines.Add(StringOfChar('-', Pred(AnItem.ItemByIndex(c).Level) * 2) + // ajoute '--' pour chaque niveau ' ' + AnItem.ItemByIndex(c).Text); if AnItem.ItemByIndex(c).count > 0 then // l'élément a des enfants appel à la procedure récursive getChilds(AnItem.ItemByIndex(c)); end; end; begin Memo1.lines.clear; // tous := 0; // selections := 0; // vue := 0; // visibles :=0; for I := 0 to Arbre.count - 1 do begin // inc(tous); // inc(vue); // racine toujours visible // if Arbre.ItemByIndex(I).IsSelected then inc(selections); // if Arbre.ItemByIndex(I).IsVisible then inc(visibles); Memo1.lines.Add(Arbre.ItemByIndex(I).Text); if Arbre.ItemByIndex(I).count > 0 then // appel procedure récursive getChilds(Arbre.ItemByIndex(I)) end; // Memo1.lines.Add(Format('Total : %d, en vue : %d, sélectionnés : %d, visibles : %d', // [tous, vue, selections, visibles])); end; |
*Visibles : Attention il faut distinguer deux visibilités
- le fait que l'élément ne soit pas visible dans l'arbre parce que son parent n'est pas élargi (IsExpanded=false);
la propriété de l'élément testée par IsVisible (valeur de la propriété visible de l'élément).
Le composant TListView n'a pas de propriété MultiSelect qui, désactivée, permettrait de n'avoir qu'un seul élément sélectionné.
Voici une solution pour un TListView* en mode Édition.
* un TListView dont l'ItemEditAppearance se termine par ShowCheck
Utilisez l'événement OnItemClick du composant.
Code delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | procedure TForm1.ListView1ItemClick(const Sender: TObject; const AItem: TListViewItem); var anItem : TListViewItem; begin ListView1.BeginUpdate; for anItem in ListView1.Items do anItem.Checked:=(AnItem=AItem) AND AItem.Checked; ListView1.EndUpdate; end; |
Réponse simple : utiliser la propriété Sorted.
Code Pascal : | Sélectionner tout |
ListBox1.Sorted:=True;
Attention, lorsque cette propriété est activée le tri sera appliqué lors de tous les nouveaux ajouts.
Oui mais si je ne veux pas de l'ordre alphabétique (par défaut) ?
La solution "facile" : utiliser l'évènement OnCompare de la ListBox.
Exemple : Ma liste ne contient que des nombres.
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | procedure TForm1.ListBox1Compare(Item1, Item2: TListBoxItem; var Result: Integer); var n1,n2 : single; begin n1:=StrToFloatDef(Item1.ItemData.Text,0); n2:=StrToFloatDef(Item2.ItemData.Text,0); if n1=n2 then result:=0 else begin if n1<n2 then result:=-1 else result:=1; end; end; end; |
Si je veux utiliser une autre valeur que text ?
Première solution : "personnaliser" l'évènement OnCompare en fonction de la colonne.
Exemple 1 : J'ai une ListBox de style DefaultItemStyle.ItemStyle = listboxitemrightdetail et je veux trier en fonction de la "colonne" détail,
la première colonne (texte) contient du texte et la seconde (détail) un montant.
Il faut, en premier lieu déclarer une variable globale (ici ColumnToSort) afin de savoir quelle colonne devra être prise en compte.
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 | procedure TForm1.ListBox1Compare(Item1, Item2: TListBoxItem; var Result: Integer); var n1,n2 : single; begin if ColumnToSort = 0 then result := CompareText(Item1.text,Item2.text) else begin n1:=StrToFloatDef(Item1.ItemData.Detail,0); n2:=StrToFloatDef(Item2.ItemData.Detail,0); if n1=n2 then result:=0 else begin if n1<n2 then result:=-1 else result:=1; end; end; end; // Utilisation procedure TForm1.btnSortDetailClick(Sender: TObject); var Compare: TFMXObjectSortCompare; begin ListBox1.Sorted:=False; ColumnTosort:=1; Listbox1.Sorted:=true; end; procedure TForm1.btnSortTextClick(Sender: TObject); var Compare: TFMXObjectSortCompare; begin ListBox1.Sorted:=False; ColumnTosort:=0; Listbox1.Sorted:=true; end; |
Seconde solution : plus besoin de variable globale, utiliser la procédure Sort(
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | procedure TForm1.btnDetailClick(Sender: TObject); var Compare : TFMXObjectSortCompare; begin ListBox1.Sorted:=False; // important désactiver le tri "par défaut" Compare:=function(item1, item2: TFmxObject): Integer var n1,n2 : Single; begin n1:=StrToFloatDef(TListBoxItem(item1).ItemData.Detail,0); n2:=StrToFloatDef(TListBoxItem(item2).ItemData.Detail,0); if n2=n1 then result:=0 else begin if n2>n1 then Result := 1 else Result := -1; end; end; ListBox1.Sort(Compare); ListBox1.RealignContent; // redessine la liste end; |
BONUS : Comment changer l'ordre de DESCendant en ASCendant et vice-versa ?
Encore une fois cela passera par l'ajout d'une variable booléenne ou autre qui fera office d'indicateur du tri à faire.
Exemple : Application à l'évènement OnCompare, variable globale TriAscendant de type booléen.
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | procedure TForm1.ListBox1Compare(Item1, Item2: TListBoxItem; var Result: Integer); var n1,n2 : single; begin if ColumnToSort = 0 then result := CompareText(Item1.text,Item2.text) else begin n1:=StrToFloatDef(Item1.ItemData.Detail,0); n2:=StrToFloatDef(Item2.ItemData.Detail,0); if n1=n2 then result:=0 else begin if n1<n2 then result:=-1 else result:=1; end; end; if TriAscendant then Result:=Result * -1; end; |
Tout d'abord, une remarque : la plupart du temps un TPanel n'est qu'un TRectangle donc si vous voulez changer régulièrement la couleur autant utiliser ce dernier.
Si vous voulez absolument utiliser un TPanel alors voici une astuce simple :
Code Delphi : | Sélectionner tout |
1 2 3 4 | if (Panel1.ControlsCount >= 1) and (Panel1.Controls[0] is TShape) then (Panel1.Controls[0] as TShape).Fill.Color := TAlphaColorRec.Red; // uses System.UITypes |
Quelques styles FMX utilisent non pas un TRectangle (ou plus génériquement un TShape) comme ressource de style nommée « panelstyle » mais un TCustomStyleObject. Dans ce cas, le changement de couleur de s'applique pas. |
Méthode dessin : Utilisation de l'évènement OnDrawColumnHeader
Utilisation de l'unité FMX.TextLayout
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 | procedure TLigne.GrilleDrawColumnHeader(Sender: TObject; const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF); var tl: TTextLayout; begin tl := TTextLayoutManager.DefaultTextLayout.Create; try tl.BeginUpdate; try // effacer le canvas // inconvénient la couleur n'est pas sensible au Style appliqué Canvas.Fill.Color := TAlphaColors.LightGrey; Canvas.FillRect(Bounds, 0, 0, [], 1); tl.TopLeft := Bounds.TopLeft; tl.MaxSize := PointF(Column.Width, Column.Height); tl.Font:=GrillePointure.TextSettings.Font; tl.Text := Column.Header; // Value //alignement à gauche TTextAlign.Leading, au centre TTextAlign.Center, à droite TTextAlign.Trailing tl.HorizontalAlign := TTextAlign.Center; finally tl.EndUpdate; end; tl.RenderLayout(Canvas); finally tl.Free; end; end; |
Prendre en compte le style reste possible mais dépendant du fichier style utilisé (hors sujet de cette FAQ).
Je propose donc cette méthode qui fonctionnera quel que soit le fichier style utilisé.
Méthode accès directs aux entêtes : Utilisation de l'unité FMX.Header
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 | // obtention de l'accès au THeader var Header : THeader :=THeader(maGrille.FindStyleResource('header')); if assigned(Header) then // Changer l'alignement //alignement à gauche TTextAlign.Leading, au centre TTextAlign.Center, à droite TTextAlign.Trailing TheaderItem(Header.Items[<numcolonne>]).TextSettings.HorzAlign:=TTextAlign.Center; |
Mon premier conseil : Anticipez.
Si vous créez les colonnes au runtime, déclarez le bon type :
plutôt que le type par défaut TColumn (qui est en fait un TStringColumn par défaut). Cela vous permettra d'avoir en plus le bon éditeur associé.
Si vous utilisez LiveBindings pour lier votre grille à des données, durant la conception, déclarez les colonnes (Clic droit sur la grille, option : Éditeur de colonnes) vous pourrez alors, entre autres,
indiquer l'alignement souhaité (propriété Alignment). L'association d'un éditeur se fera (au besoin) en modifiant la propriété ColumnStyle.
Plein d'autres raisons peuvent se liguer pour que ces anticipations ne soient pas possibles.
Il vous reste alors une méthode, l'utilisation de l'évènement OnDrawColumnCell ; cependant la prise en compte des styles est difficile.
Je propose cette méthode qui fonctionnera :
- quel que soit le fichier style utilisé ;
- que les colonnes soient déclarées (via l'éditeur de colonne) ou pas.
Ajoutez ce helper au sein de votre unité :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | type TColumnHelper = class helper for TColumn procedure ApplyAlignment(Alignment : TTextAlign) ; end; ... implementation ... {TColumnHelper} procedure TColumnHelper.ApplyAlignment(Alignment: TTextAlign); begin Self.HorzAlign:=alignment; Self.Changed; end; |
À utiliser de cette manière :
Code Delphi : | Sélectionner tout |
1 2 | // alignement à gauche TTextAlign.Leading, centrer TTextAlign.Center, aligner à droite TTextAlign.Trailing StringGrid1.Columns[<numero de colonne>].ApplyAlignment(TTextAlign.Trailing); |
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.