I. Introduction▲
Les dernières versions de Delphi permettent de modifier le style d’affichage des interfaces graphiques, et ce à partir de l’environnement de développement. Cette fonctionnalité est similaire à celle des sites web avec le couple HTML et CSS. Ce qui fait qu’elle permet de modifier l’aspect de l’interface sans toucher au contenu.
Malheureusement, le sujet est très mal documenté et l’on voit très vite qu'il y a beaucoup de paramètres à prendre en compte. C’est pourquoi, après beaucoup de tâtonnements, j’ai décidé de vous faire profiter de mon expérience.
Je précise que ce modeste guide est destiné avant tout aux débutants et il fait sans doute l’impasse sur de nombreux points, mais il est destiné à mettre un pied à l’étrier. De même, je n’aborde ici que le cas des applications multiplates-formes et je ne parlerai pas des applications VCL. Les exemples que je montre s’appliquent essentiellement à Windows (version 10), mais ils sont aussi valides pour les autres OS (Android, OsX et IOS).
Les exemples qui sont montrés ont été faits sur les versions 11.3 et 12.2 de Delphi.
II. Quelques informations sur les styles▲
Les styles de votre application sont stockés dans un composant TStyleBook.
Pour que les styles contenus dans votre composant TStyleBook soient appliqués, il faut attribuer le composant TStyleBook à la propriété StyleBook du composant TForm.
Dans un même TStyleBook on peut spécifier les styles en fonction de l’OS.
Ici, on a défini cinq cas. Le premier est Default qui s’appliquera à tout environnement autre que ceux figurant dans la liste. Les autres s’appliqueront dans leur environnement spécifique.
Enfin, le contenu de votre TStyleBook peut être sauvegardé dans un fichier et il est possible de charger ce fichier. Ainsi, si vous disposez de plusieurs fichiers de style, vous pouvez permettre à l’utilisateur de votre fichier de passer d’un style à un autre grâce à un menu ou un bouton comme on peut le voir dans la figure ci-dessous.
Un style peut être appliqué à un ou plusieurs composants de l’interface ou à tous les composants de même type. Vous pouvez facilement faire ce choix dans l’interface en faisant un clic droit sur un composant et en choisissant dans le menu déroulant l'option correspondante.
Sur la figure ci dessus, on a sélectionné l’option « Modifier un style personnalisé ». Ce qui implique que ce style ne sera appliqué qu’à mon composant Label1 qui est posé sur la fiche. Maintenant, si je choisis l’option « Modifier le style par défaut », alors ce style sera appliqué à tous les composants du type TLabel présents sur ma fiche sauf si on a attribué une autre valeur à la propriété stylebook du composant en question.
Pour savoir si un style est un style par « défaut », il suffit d’examiner la propriété StyleName. Si le nom est sous la forme nom du composant + Style, il s’agit d’un style par défaut, sinon c’est un style personnalisé. Par exemple LabelStyle s’applique aux composants TLabel.
On va maintenant voir ce qu’il est possible de faire.
III. Modification du style des TLabel▲
Nous allons commencer par un exemple simple : le composant TLabel. Je souhaite changer la police de caractères, la taille des lettres et leur couleur. Pour ce faire je crée un projet Multiplates-formes vierge et je dépose dessus un TLabel. Je fais un clic droit et je sélectionne l'option Modifier un style par défaut. L'éditeur bascule automatiquement sur l'interface du concepteur de style ; son fonctionnement est relativement bien décrit dans la documentation (cf doc embarcadero).
Avec cette méthode, un composant TStyleBook a été automatiquement ajouté au projet. Et l’on voit que le style a été nommé LabelStyle, ce qui implique qu’il s’appliquera à tous les TLabel.
Par la suite, je procéderai de la même manière pour chaque élément, ceci afin de n'avoir que les éléments de style correspondant au composant.
Mais revenons à notre TLabel. Dans le concepteur de style, on a en haut à gauche l'arborescence du style en dessous la liste des paramètres de l'élément de style sélectionné. Au centre, le dessin des éléments composant le style, et à droite, le rendu final du style.
Le style du TLabel (LabelStyle) est simple il est composé d'un TLayout dans lequel est mis un TText. Comme on veut changer uniquement la police de caractères, la taille des lettres et leur couleur, on va agir sur le paramètre TextSettings de l’élément TText. Dans mon cas, j'ai choisi la police Comic Sans MS d'une taille 14 et de couleur Navy.
Une fois cela fait, il suffit de fermer le concepteur de style et de sauvegarder les modifications.
Par la suite, si l’on dépose un autre TLabel sur la fiche, il aura son texte écrit avec la police Comic Sans MS d'une taille 14 et de couleur Navy.
III-A. Adaptation du style à d’autres OS▲
Le style qu’on vient de définir s’appliquera à l’OS Windows 10 puisque c’est la plateforme sélectionnée dans le concepteur de style. Maintenant, si l’on veut l’adapter à d’autres OS, il suffit de sélectionner (ou d’ajouter) la plateforme dans le concepteur de style, puis de procéder aux mêmes modifications. Ou encore plus simple, faire un copier-coller et faire éventuellement quelques ajustements. Par contre, si vous n’avez pas d’exigences particulières en fonction de l’OS, dans ce cas le mieux est de ne garder que la plateforme default et de mettre tous vos styles dedans.
IV. Modification du style des TListBox▲
Maintenant on va passer à plus complexe : la modification du style d'une TlistBox, et voici ce que je veux obtenir:
Pour cela, je vais dans un premier temps analyser le style "normal" d'une TListBox. Donc je procède comme pour le TLabel, je crée un nouveau projet sur lequel je dépose une TListBox, je fais un clic droit dessus et je sélectionne l'option Modifier un style par défaut.
IV-A. Analyse du style original▲
On remarque tout de suite que la structure est plus complexe et qu'il y a en plus de l'élément ListboxStyle un certain nombre d'autres éléments qui sont présents. C’est parce qu’une TListBox est constituée d’éléments différents (voir figure ci-dessous). Pour obtenir ce que l’on veut, il faudra modifier tous ces éléments.
Je conseille tout d’abord de renommer les noms à rallonge des styles de manière à ce qu’ils soient plus lisibles. En effet, on va par la suite utiliser ces noms pour pointer les styles à appliquer aux différents éléments constitutifs de notre listbox stylisée.
Ancien nom |
Nouveau nom |
Élément constitutif |
htrackhthumbstyle1 |
scrlbar_hcurs |
Curseur de la barre de défilement horizontale |
vscrollbarscrollbarbottombutton1 |
scrlbarbtn_bottom |
Bouton bas de la barre de défilement verticale |
vscrollbarscrollbarhtrackstyle1 |
scrlbar_htrack |
Barre de défilement horizontale |
vscrollbarscrollbarleftbutton1 |
scrlbarbtn_left |
Bouton gauche de la barre de défilement horizontale |
vscrollbarscrollbarrightbutton1 |
scrlbarbtn_right |
Bouton droit de la barre de défilement horizontale |
vscrollbarscrollbartopbutton1 |
scrlbarbtn_top |
Bouton haut de la barre de défilement verticale |
vscrollbarscrollbarvtrackstyle1 |
scrlbar_vtrack |
Barre de défilement verticale |
vsmallscrollbarscrollbarhtrackstyle1 |
scrlbar_htrack_small |
Petite barre de défilement horizontale |
vsmallscrollbarscrollbarvtrackstyle1 |
scrlbar_vtrack_small |
Petite barre de défilement verticale |
Vtrackvthumbstyle1 |
scrlbar_vcurs |
Curseur de la barre de défilement verticale |
ListBoxstyleScrollBarStyle1 |
scrlbar_scrlbar |
Style définissant les barres de défilement horizontale et verticale |
IV-B. Modification du style original▲
Après un certain nombre d’expérimentations douloureuses, je me suis rendu compte qu’il valait mieux commencer par les éléments les plus simples et ne dépendant d’aucun autre style. Puis on va progressivement modifier les autres éléments.
Plusieurs éléments répondent à cette condition, comme le fond ou les boutons d'extrémité des barres de défilement. Mais avant, je vais expliquer comment sont construits les styles à partir d’un bitmap.
IV-C. Construction d’un style à partir de bitmaps▲
Les éléments qu’on dépose sur la fiche de conception comme les boutons sont en fait des images qui ont été conçues soit par vous-même soit par votre dessinateur préféré. Dans tous les cas, elles ont des dimensions bien précises. Or, il se trouve que vos boutons sur votre interface graphique n’auront pas forcément les mêmes dimensions, et pire même, ne respecteront pas le ratio hauteur largeur.
Par exemple, comme on peut le voir sur cette figure, mon dessinateur m’a livré le graphisme A pour mes boutons, mais sur mon interface je veux qu’il ressemble à B. Un simple ré-échantillonnage de l’image ne suffit pas, car il y aura des déformations. Alors, comment faire ?
La solution adoptée consiste à découper l’image en 9 zones.
Il en résulte 3 types de zones. 4 coins C, 4 bords B et une partie centrale A. Lorsque l’élément est dessiné, ces 4 coins C ne changent pas de dimensions. Par contre, les bords vont s’allonger ou se réduire selon leur direction. Quant à la partie centrale, elle va augmenter ou diminuer selon les deux directions.
Donc, si l’on considère notre exemple de départ où l’on est passé d’un rectangle horizontal à un rectangle vertical, voici ce qui c’est passé. On a augmenté les deux côtés verticaux, et on a réduit les deux côtés horizontaux et la partie centrale a été modifiée de la même façon sur ses deux dimensions. Ce qui fait que l’aspect général de l’image a bien été préservé tout en ayant la forme désirée.
La définition des zones est faite dans l’éditeur BitmapLinks. Charge à vous de faire en sorte que le choix des zones soit fait de manière à ce que le rendu soit le plus satisfaisant possible. C’est surtout important si vous utilisez des textures comme c’est le cas dans mon exemple.
De plus, dans l’éditeur BitmapLinks, vous avez la possibilité de définir différentes résolutions. Chaque résolution est un couple image et facteur d’échelle. Ceci permet d’avoir un meilleur rendu en fonction de l’affichage. En fonction de l’OS, différentes résolutions « typiques » vous sont proposées, mais vous êtes libre d’en ajouter, supprimer ou modifier.
On va mettre cette technique en pratique pour la suite.
IV-D. Modification des styles▲
IV-D-1. Le fond de la ListBox▲
La listbox doit avoir l’aspect d’une ardoise entourée d’une bordure de bois. Pour réaliser ça, j’ai été chercher sur le web des textures d’ardoise et de bois. Puis j’ai fait dessiner l’image suivante. J’ai choisi une dimension d’image moyenne, car je ne voulais pas quelque chose de trop volumineux, mais il fallait qu’elle soit suffisamment grande pour que le rendu soit correct.
Ensuite j’ai défini les 9 zones à l’aide de l’éditeur BitmapLinks.
Lorsque j’ai dessiné mon modèle, j’ai choisi de faire une bordure de 16 pixels, et comme vous pouvez le voir, les bordures se coupent à 45° comme dans la réalité. Donc, pour préserver cette découpe à 45°, j’ai défini mes coins comme ayant une dimension de 16x16.
Le fond (background) contient un élément content qui contient lui-même un élément selection.
L’élément content est un TLayout qui comme son nom l’indique va contenir l’ensemble des éléments de la liste. La seule opération que l’on va faire sur cet élément est de régler les marges de manière à ce que les écritures ne soient pas sur les bordures en bois. Comme les bordures ont une épaisseur de 16 pixels, on règle toutes les marges à 16 sauf la marge de droite.
L’élément selection est un TStyleObject qui va être utilisé pour signaler le ou les éléments sélectionnés. Si l’on regarde sur le style original, on voit que cet élément est un bitmap et donc on en a construit une aussi. Il s’agit d’un rectangle aux coins arrondis sur un fond transparent. Là encore, on a défini les 9 zones à l’aide de l’éditeur BitmapLinks. Maintenant que les éléments simples du fond ont été modifiés, on va passer aux autres éléments comme les barres de défilement en commençant par les boutons d’extrémités.
IV-D-2. Les barres de défilement▲
IV-D-2-a. Les boutons▲
Tout d’abord, il faut savoir qu’un bouton peut prendre 4 états :
- focused ;
- hot ;
- normal ;
- pressed.
Chacun de ces états répond à une action de l'utilisateur sur le bouton et le TButtonStyleObject offre la possibilité de définir un bitmap pour chacun de ces états. On peut le voir en examinant les propriétés FocusedLink,HotLink,NormalLink et PressedLink.
Prenons en exemple le bouton vers le bas (scrlbarbtn_bottom).
Il est composé de 2 TButtonSyleObject . L’un est pour le fond et l’autre pour le symbole à afficher. Si l’on regarde les propriétés FocusedLink,HotLink,NormalLink et PressedLink, on peut voir comment sont définis les bitmaps. Dans le cas du symbole pour le bouton bas, on a une image de 11x9 pixels et pour ce qui est des fonds, les images font 16x16. On va créer 2 images, une pour les fonds et une pour les symboles.
Et à l’aide de l’éditeur BitmapLinks, on va définir les zones à prendre pour chacun des états. Une fois cette opération réalisée, on va modifier les propriétés leftbutton,rightbutton,topbutton et botombutton du style ListBoxstyleScrollBarStyle1 en leur attribuant les noms des styles qu’on vient de modifier. Ainsi, scrollbarleftbutton devient scrlbarbtn_left, scrollbarrightbutton devient scrlbarbtn_right, scrollbartopbutton devient scrlbarbtn_top et scrollbarbottombutton devient scrlbarbtn_bottom.
IV-D-2-b. La piste centrale▲
Maintenant, on va s’occuper des styles des pistes centrales scrlbar_htrack et scrlbar_vtrack. L’examen ces deux styles montre qu’ils sont composés de deux éléments, un fond et un bouton.
Donc on va modifier ces styles de la même façon que pour les boutons situés aux extrémités des barres de défilement. À savoir créer un bitmap représentant les 4 états possibles du bouton. Puis, pour chaque état, on affecte la portion de bitmap correspondante.
Pour la piste, il n’y a qu’un état disponible, et c’est la propriété SourceLink qu’on va modifier.
On va créer 2 bitmaps une pour la piste verticale (16x380) et une pour la piste horizontale (380x16). Et comme pour tous les autres bitmaps, on définit les zones dans l’éditeur BitmapLinks.
Finalement on passe de ceci à cela
On va maintenant affecter tous ces styles aux différents composants de TListBoxStyle.
IV-D-3. Affectation des styles▲
On va modifier le contenu de la propriété StyleLookup des différents éléments ainsi.
Style |
Affecté à la propriété StyleLookup de l’élément |
scrlbar_hcurs |
thumb dans le style scrlbar_htrack |
scrlbarbtn_bottom |
Bottombutton dans le style scrlbar_scrlbar |
scrlbar_htrack |
htrack dans le style scrlbar_scrlbar |
scrlbarbtn_left |
leftbutton dans le style scrlbar_scrlbar |
scrlbarbtn_right |
rightbutton dans le style scrlbar_scrlbar |
scrlbarbtn_top |
topbutton dans le style scrlbar_scrlbar |
scrlbar_vtrack |
vtrack dans le style scrlbar_scrlbar |
scrlbar_vcurs |
thumb dans le style scrlbar_vtrack |
scrlbar_scrlbar |
hscrollbar et vscrollbar dans ListBoxstyle |
Le résultat final donne ceci.
Il faut maintenant modifier les écritures des éléments de la listbox. Le style des éléments de listbox est un style à part qui n’est pas contenu dans le style des TListBox.
IV-D-4. Modification du style des éléments de la liste▲
Les éléments d’une liste sont des TlistBoxItem auxquels on peut affecter un style. Il est à noter qu’il est possible de faire énormément de choses en modifiant le style de ce composant et cela fera l’objet d’un autre chapitre. Pour le moment, on va simplement se contenter, comme pour le Tlabel, de changer la valeur de quelques propriétés.
Donc, pour ajouter un style par défaut aux TlistBoxItem, on procède comme pour le Tlabel en sélectionnant un élément de la listbox sur la fiche, puis en effectuant un clic droit et sélection dans le menu contextuel du choix « Modifier le style par défaut ». Dans le StyleBook, 2 nouveaux styles vont apparaître : ListBoxItemstyle et ListBoxItemstyleChechBoxStyle1.
On va simplement modifier la propriété « text » de ces deux styles. Pour le ListBoxItemstyle, il s’agit d’un TActiveStyleTextObject. On ne va pas trop entrer dans les détails, mais ce style permet de colorer d’une manière différente le texte quand il est « activé ». L’activation est définie par la propriété ActiveTrigger. Dans notre cas, nous allons la laisser telle qu’elle, à savoir que l’activation est appliquée quand un élément de la liste est sélectionné. On ne modifie que la propriété ActiveColor. Ensuite, tout comme pour le Tlabel, on modifie la propriété TextSettings.
Pour ce qui est du ListBoxItemstyleChechBoxStyle1 c’est un peu plus complexe. Il s’agit du style qui sera appliqué si la listbox est configurée pour contenir une case à cocher. Ce style est affecté à la propriété check du style ListBoxItemstyle.
On peut voir sur la figure ci dessus sa composition. On va déjà s’intéresser à l’élément text. Dans un premier temps, on lui applique les mêmes modifications de la propriété TextSettings que pour celle du style ListBoxItemstyle.
On va pour l’instant s’arrêter là, mais il faut savoir que ce style offre plus de possibilités, car c’est un TButtonStyleTextObject. Ce qui implique qu’on peut modifier l’affichage en fonction des quatre états possible pour un bouton.
V. Conclusion▲
Dans cet article, je vous ai montré quelques exemples de ce qu’il était possible de faire pour appliquer un style à votre application. Je suis bien conscient d’avoir omis un certain nombre de choses, mais le but était de faire découvrir ce système. Système qui offre une immensité de possibilités de customisation d’une application sans à avoir à faire des tonnes de lignes de code. C’est une fonctionnalité très puissante, mais difficile à maîtriser, car la documentation est très faible sur le sujet et manque cruellement d’exemples ce qui est bien dommage. Il existe quelques ouvrages comme « Delphi GUI Programming with FireMonkey » d’Andréa Magni (ISBN 978-1-78862-417-6) qui vous permettront d’approfondir le sujet. De même, vous pouvez obtenir des styles prêts à l’emploi avec getit et les étudier. Mais avant tout, si vous êtes intéressé par ce sujet, je vous invite à faire vos propres expériences. De mon côté, en fonction de ma disponibilité, je publierai d’autres articles sur le sujet.