Introduction▲
Préambule▲
Ma première approche des styles a été douloureuse. J'ai tellement galéré sur les Styles FMX pour une application « simple » que je voudrais éviter aux autres, en particulier aux membres de www.developpez.net, d'avoir à faire les mêmes recherches que moi (longues heures de vidéos anglaises, « googlisages » intensifs, ouverture des programmes exemples, etc.). Voici un lien regroupant une partie de mes lectures et visionnages :
Mise en garde▲
Pour les « vieux delphistes », l'éditeur de style est déroutant. En effet, on a tendance à vouloir utiliser l'écran de design pour poser nos formes de base, et attendre un rendu à la mesure des designs d'une forme classique. Las, nous devons vite déchanter, les composants doivent être « posés » dans l'arbre de structure et le rafraîchissement du rendu n'est pas toujours instantané.
Mes premiers conseils : sauvegardez souvent, nommez (propriété StyleName) tous les éléments et ayez beaucoup de patience !
Objectif▲
Pour comprendre : un label avec bouton▲
Pour commencer, et surtout essayer de comprendre, nous allons créer un style pour la recherche de répertoire. Tout d'abord, poser un TSyleBook sur la forme, et un TLabel (cela aurait pu être un TEdit mais je voulais faire simple). Il aurait été facile de faire la même chose directement et sans style en posant par exemple dans un Layout : un TRectangle, un TLabel, un TButton, un TImage comme sur la droite de l'image.
De fait, nous allons faire la même chose avec l'éditeur de style. Double-cliquez sur le TStyleBook que j'ai nommé Resource1 et posez, dans l'arbre de structure, un premier TLayout et là : première surprise, on ne voit rien !
Pas de panique, ouvrez l'arborescence, cliquez sur le Layout, l'écran de design se rafraîchit et on peut le déplacer et le retailler à souhait. Profitons-en pour rajouter dans ses propriétés son StyleName (dans mon exemple : BrowseDirStyle).
Cliquez sur Appliquer et Fermer puis ré-ouvrez le style pour voir le résultat.
Ça y est, le nom est enfin pris en compte, mais si la taille du Layout est gardée, il est de nouveau centré dans la fenêtre de design. On n'en a pas fini avec les surprises de ce genre et il faudra faire de nombreuses fois la manipulation « Appliquer et Fermer + Ré-Ouvrir », que je désignerai maintenant sous le nom de A.F.R.O.
Déposons ensuite dans ce Layout deux autres Layouts, un qui sera cadré à droite, dans lequel on ajoutera un bouton (TButton), qui contiendra à son tour une image et l'autre aligné à la zone client, qui contiendra un TRectangle contenant lui-même un TLabel pour finaliser l'ensemble.
Et voilà, nous sommes tombés dans un nouveau piège. (cf. mes premiers conseils).
Impossible de se positionner sur le premier Layout, car ils ont le même nom ! Nommez celui qui est accessible (StyleName), faites la manipulation A.F.R.O (qui va devenir célèbre), et recommencez pour le second Layout.
Sortis de ce piège, il ne nous reste plus qu'à finaliser l'ensemble. Ensuite, on va nommer (au minimum avec la propriété StyleName) les deux composants que nous allons utiliser (le label et le bouton) pour pouvoir y accéder. Pour rafraîchir le design, n'hésitez pas à cliquer sur un des parents du composant que vous venez d'ajouter (cf. mise en garde).
Vous remarquerez que j'ai nommé (StyleName) le TLabel ‘Text', une petite astuce qui va permettre d'accéder à cette propriété directement.
Il nous reste maintenant à appliquer ça à notre forme et notre code. Posons un TLabel sur la forme et mettons ses propriétés StyleName=Resources et StyleLookup=BrowsedirStyle et la magie opère.
Pour changer l'intitulé du label, il suffira d'utiliser le code suivant :
MonLabelStylé.Text := 'Sélectionnez un répertoire'
;
Malheureusement, l'astuce pour le label ne fonctionnera pas pour le bouton et nous devrons lier l'événement par code :
MonLabelStylé.StylesData[‘
;BrowseBtn.OnClick'] := TValue.From<TNotifyEvent>(Button3Click);
où Button3Click est une procédure à déclarer et bien sûr à coder.
Personnaliser les items d'une liste▲
Passons maintenant au style des items de la liste. Chaque item va contenir : une image, deux textes (un pour le nom de l'image, l'autre pour sa taille) et enfin un bouton qui nous permettra de faire un traitement quelconque (par exemple : afficher l'image en grand).
Première étape, ajouter un TLayout et lui donner un StyleName (ListItem) et A.F.R.O. Puis, ajouter les différents éléments : un TLayout cadré à gauche contenant un TImage (‘Icon') centré, un TLayout cadré à droite contenant un bouton (‘Info') et enfin un dernier TLayout qui prendra le reste de la place (alClient) et contiendra deux TLabels (‘Size' et ‘Text').
L'exercice est assez délicat, la marche à suivre est cependant la même que pour notre style de début. N'oubliez pas la manipulation A.F.R.O (il m'est arrivé de ne plus voir du tout le dessin de mon style et d'être obligé de recommencer malgré tout).
Une fois le style terminé, passons à la codification.
procedure
TForm3.Button3Click(Sender: TObject);
var
Info : TSearchRec; // structure de recherche
chemin : String
; // répertoire sélectionné
Item: TListBoxItem; // item de la liste
begin
// Note : SelectFolder est une fonction se trouvant dans une unité
// séparée : winfolderselectutils.pas
MonLabelStylé.Text := SelectFolder('Sélectionnez le répertoire'
);
Chemin := IncludeTrailingPathDelimiter(label1.Text);
try
Listbox1.BeginUpdate; // passage en mode update
// efface une précédente recherche si nécessaire
Listbox1.Items.Clear;
{ Recherche de la première entrée du répertoire }
If
FindFirst(Chemin+'*.jpg'
,faAnyFile,Info)=0
Then
Begin
Repeat
If
(Info.Attr And
faDirectory) = 0
then
begin
// Création de l'item
Item := TlistBoxItem.Create(nil
);
// affectation à la liste
Item.Parent := ListBox1;
// Stockage nom complet
Item.TagString := Chemin+Info.Name;
Item.StyleLookup := 'ListeItem'
; // style de l'item
Item.Text := info.name; // nom du fichier
// Hauteur de l'item (pour ne pas prendre la hauteur par défaut)
Item.Height := 60
;
try
// remplissage de l'image (utilisation de vignette)
Item.ItemData.Bitmap.LoadThumbnailFromFile(Item.TagString,Item.Height,Item.Height);
except
end
;
// Taille de l'image si > 1Mo
if
info.Size > SizeM
// en Méga Octets
then
Item.StylesData['Size.Text'
] := Format('%3.3f Mo'
,[info.Size/sizem])
// sinon en Kilo Octets
else
Item.StylesData['Size.Text'
] := Format('%3.3f Ko'
,[info.Size/sizek]);
// très utile pour la sélection de l'item
Item.StylesData['info.tag'
] := ListBox1.Items.Count-1
;
// affectation de l'événement au bouton info de l'item
Item.StylesData['info.OnClick'
] := TValue.From<TNotifyEvent>(DoInfoClick); // OnClick du bouton
end
;
Until
FindNext(Info)<>0
; // recherche
FindClose(Info); // fin de recherche
End
;
finally
ListBox1.EndUpdate; // fin de mise à jour, force le dessin
end
;
end
;
En plus des commentaires, quelques explications.
Concernant l'affectation des valeurs aux labels, pour le style précédent, j'avais utilisé une astuce en donnant comme StyleName la valeur ‘Texte' (astuce que j'ai d'ailleurs réutilisée pour le nom du fichier) ; mais comment faire lorsque l'on a plusieurs Labels ? On récupère la propriété via StylesData[‘nom de Style.propriété'].
Pour l'image, je n'ai pas accédé à la propriété Bitmap de la même manière, mais par l'intermédiaire de ItemData.Bitmap.
Enfin, notez l'apparition d'une nouvelle propriété pour un item de liste : TagString, très pratique pour le stockage du nom complet de l'image.
Conclusion▲
Dans ce premier tutoriel, je n'ai fait qu'effleurer le sujet. Je n'ai pas abordé les styles déjà fournis dans des fichiers *.style et me suis cantonné à des styles contenus dans une ressource (en fait, inclus dans le dfm de la forme). Pour aller plus loin, je vous renvoie à une partie de ma liste de lectures/visionnages. Je vous conseille également d'installer le petit add-on de Marco Cantù permettant de voir le source des styles. En effet, sous XE4, le composant StyleBook stocke les informations de style dans un format binaire compressé, rendant la chose plus difficile à éditer manuellement.
Source complet du programmeSources
Un grand merci à Alcatîz pour m'avoir mis le pied à l'étrier, et surtout pour avoir corrigé la mise en forme de ce premier tutoriel, ainsi qu'à Cédric DUPREZ et Philippe DUVAL pour leur relecture.