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é.

Image non disponible

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.

Image non disponible

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 !

Image non disponible

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.

Image non disponible

Ç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.

Image non disponible

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).

Image non disponible

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 :

 
Sélectionnez
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 :

 
Sélectionnez
MonLabelStylé.StylesData[&#8216;BrowseBtn.OnClick'] := TValue.From<TNotifyEvent>(Button3Click);

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).

Image non disponible

Une fois le style terminé, passons à la codification.

 
Sélectionnez
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.