Introduction aux Styles FireMonkey XE4

Mes premiers pas

Serge Girard

Les contrôles VCL sont dessinés par l'OS alors que les contrôles le sont entièrement par FireMonkey lui-même. Cela veut dire que FireMonkey, et par là même votre application, a un contrôle total sur chaque rendu de votre application. Les styles permettent de changer radicalement l'apparence de votre application ou d'un contrôle particulier.

Commentez

- Titre : Introduction aux Styles FireMonkey XE4

- Auteur : Serge Girard

- Parution : 17 février 2014

- Mise à jour : 27 février 2014

- Public visé :

- Licence : 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 ® 2014 Serge Girard. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Introduction

- Préambule

- Mise en garde

- Objectif

- Pour comprendre : un label avec bouton

- Personnaliser les items d'une liste

- Conclusion

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 :

http://www.tindex.net/FireMonkey/Styles.html.

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

Mon objectif est de faire, sous Windows, la liste des images JPG d'un répertoire donné.

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[&#8216;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 programme

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.