Utilisation des listes d'images de TImageList en tant que collections centralisées d'images

De RAD Studio
Aller à : navigation, rechercher

Remonter à Conception d'applications FireMonkey

Les listes d'images TImageList de FireMonkey fournissent des outils complets pour l'utilisation des collections centralisées de petites images adaptées aux éléments de l'interface utilisateur (contrôles, menus, etc.) dans les applications FireMonkey. Dans FireMonkey, les listes d'images TImageList ont le même rôle que les listes d'images Vcl.Controls.TImageList dans la VCL, excepté qu'elles fournissent des fonctionnalités plus avancées. Dans FireMonkey, les listes d'images TImageList sont utilisées pour gérer efficacement de grands ensembles d'icônes ou de bitmaps. Elles sont par ailleurs pratiques à utiliser dans les applications multiplates-formes.

FireMonkey est un framework multiplate-forme (Windows, iOS, OS X et Android). Les applications FireMonkey fonctionnent donc sur des périphériques dotés d'écrans de différentes densités et résolutions. L'utilisation des bitmaps multi-résolutions de FireMonkey permet un affichage correct des images et des icônes de vos applications FireMonkey dans différentes densités, résolutions et plates-formes (Windows, iOS, OS X et Android). Un bitmap multi-résolution est une collection d'éléments bitmap fournissant la même image, mais utilisant des échelles différentes.

Raisons pour lesquelles nous recommandons l'utilisation des listes d'images

Dans une application GUI, nombreux sont les contrôles (par exemple les boutons, les éléments de menu, les éléments de différentes listes) qui contiennent de petites images (icônes, pictogrammes ou widgets). Par exemple, TMenuItem a la propriété Bitmap. En utilisant cette propriété, vous pouvez charger une image à partir d'un fichier. Il s'agit du moyen le plus évident et le plus pratique de charger des images dans vos applications. Dans chaque nouveau contrôle, vous pouvez charger et afficher une image spécifique.

Il existe un autre moyen : stocker toutes les images utilisées dans une application au sein d'une collection centralisée et, pour chaque contrôle, stocker seulement une référence à une image dans cette collection. Vous pouvez, par exemple, utiliser une image à partir d'un style. Prenons le cas d'un bouton. Dans l'inspecteur d'objets, sélectionnez la propriété StyleLookup, cliquez sur la flèche pour développer la liste déroulante, et sélectionnez searchtoolbutton. L'icône Loupe apparaît pour le bouton. Nous conservons cette possibilité mais nous considérons qu'elle convient plutôt à une collection fixe des icônes les plus standard. Cependant, les applications réelles nécessitent souvent que vous chargiez et stockiez des icônes personnalisées. Dans ce type de situation, le composant TImageList peut être très utile.

L'algorithme schématique de l'utilisation de TImageList peut ressembler à ce qui suit :

  1. Sur une fiche (de préférence sur un module de données créé spécifiquement), placez une liste d'images TImageList (composant non visible).
  2. Chargez vos images dans cet objet TImageList.
  3. Dans l'inspecteur d'objets, sélectionnez la propriété Images de votre contrôle, cliquez sur la flèche pour développer la liste déroulante, puis sélectionnez la référence à l'objet TImageList.
  4. Dans la propriété ImageIndex, sélectionnez le numéro de l'image (dans l'objet liste d'images) que vous souhaitez afficher.

Pour chaque nouveau contrôle, répétez les étapes 3 et 4. Si l'objet TImageList ne contient pas une image souhaitée, répétez l'étape 2. Dans un premier temps, cet algorithme peut sembler trop compliqué. Pour expliquer les avantages de cette procédure et de l'utilisation de TImageList par rapport à la simple sélection d'une image souhaitée dans un dossier, nous vous présentons les exemples suivants d'utilisation de TImageList.

Premier exemple : La collection d'images d'un programmeur expérimenté peut contenir plus de 9 000, voire 10 000 éléments. Il peut s'avérer difficile de rechercher une image spécifique au sein d'une telle collection. D'un autre côté, même les applications relativement compliquées peuvent utiliser de 100 à 200 images. Dans une application, de nombreux contrôles peuvent utiliser la même image (ou une image similaire). Il est donc souhaitable de préserver une certaine cohérence dans l'utilisation de ces images. Par exemple, il y a environ 1 an, lors du développement de la 1re version de votre programme, votre ancien collègue a assigné au bouton Enregistrer une icône représentant une "disquette bleue de 3 pouces". A présent, vous développez la nouvelle version du programme. Vous devez créer une nouvelle fiche contenant un bouton Enregistrer similaire et lui assigner la même icône. Cependant, la recherche de cette icône peut s'avérer difficile. En utilisant l'objet TImageList, vous n'auriez pas ce problème car vous pourriez simplement sélectionner cette icône dans la liste déroulante développée de votre objet TImageList.

Second exemple : Supposons que votre patron décide que c'est le moment d'utiliser l'icône représentant une lampe moderne économe en énergie plutôt que l'icône de la lampe à incandescence devenue obsolète. Combien de contrôles (et éléments de menu) utilisent cette icône ? Combien de fois devez-vous changer toutes ces icônes ? Si toutes les icônes sont stockées dans une collection centralisée d'images, ce type de remplacement se transforme en opération d'une grande simplicité. Dans votre collection centralisée d'images, il vous suffit de changer cette icône. Ensuite, vous pouvez également créer un module de données contenant une collection d'images (liste d'images), et ajouter ce module à plusieurs applications devant utiliser des images de cette collection.

Troisième exemple court : La création dynamique de nombreux contrôles affichant des icônes à l'exécution génère une grande quantité de données graphiques en doublon. Si nous utilisons TImageList, chaque contrôle conserve seulement un index d'une icône à dessiner dans la collection TImageList.

Nous pouvons donc dire que l'utilisation de la collection TImageList commune permet de résoudre des tâches similaires à la 'réutilisation du code' et applicables aux données graphiques.

Utilisation des listes d'images

Vous pouvez voir la vidéo présentant les étapes typiques requises pour créer une nouvelle liste d'images dans votre projet FireMonkey (EN) et la vidéo présentant l'utilisation de l'éditeur de liste d'images pour modifier les listes d'images (EN).

L'algorithme plus détaillé de l'utilisation de TImageList peut ressembler à ce qui suit :

  1. Créez un module de données et placez-le devant la fiche principale dans la liste des modules d'un projet.
  2. Ajoutez le nom de l'unité du module de données dans la section uses du module principal.
  3. En utilisant la palette d'outils, placez un objet TImageList sur le module de données.
  4. Double-cliquez sur l'objet TImageList.
    L'éditeur de liste d'images (FireMonkey) s'ouvre.
  5. Cliquez sur le bouton Ajouter.
  6. Dans la boîte de dialogue Ajouter des images, naviguez jusqu'au fichier graphique souhaité et cliquez sur Ouvrir. Par exemple, naviguez jusqu'au dossier
    C:\Program Files (x86)\Embarcadero\Studio\20.0\Images\GlyFX\Icons\XP\PNG\16x16
    et sélectionnez-y un fichier graphique.
  7. Des aperçus de toutes les images ouvertes apparaissent dans le volet Liste d'images. Vous pouvez changer l'ordre des images en les faisant glisser avec la souris.
    Remarque : Le composant TImageList lui-même n'a pas de propriétés Width et Height générales. Chaque image est mise à l'échelle pour s'adapter à la forme du contrôle qui l'affiche. Redimensionnez le volet Liste d'images et vous constaterez que les images sont redimensionnées en fonction.
    Remarque : Veuillez noter que même si vous pouvez ajouter une image de la taille de votre choix, TImageList est conçu pour conserver les nombreuses petites images qui peuvent s'afficher dans différents éléments de la GUI (boutons, éléments du menu, listes et autres). Par défaut, les images sont stockées sans aucune modification. Elles sont mises à l'échelle à la demande. Par conséquent, si vous chargez de grandes images ou photos, il est possible qu'elles ne s'affichent pas comme vous le souhaitez dans un bouton 24*24. Par ailleurs, sur un périphérique mobile, une application peut simplement bloquer par manque de ressources système.
  8. A présent, cliquez sur OK pour fermer l'éditeur de liste d'images.
  9. Sur la palette d'outils, recherchez le contrôle graphique TGlyph. La fonctionnalité TGlyph est similaire à TImage mais ne contient pas de données graphiques.
  10. Dans l'inspecteur d'objets, localisez la propriété Images du contrôle Glyph. Dans Images, la liste affiche toutes les collections TImageList connues du projet.
  11. Sélectionnez la collection TImageList souhaitée et localisez la propriété ImageIndex. ImageIndex est l'index (numéro) d'une image dans la liste d'images. La liste dans ImageIndex affiche toutes les images existant dans la collection TImageList sélectionnée. Vous pouvez sélectionner une image souhaitée ou taper un index d'entier (ImageIndex) de l'image que vous voulez afficher. S'il n'existe aucune image pour ImageIndex, aucune image n'est sélectionnée.

TGlyph hérite de TControl et peut être utilisé dans les styles pour construire des contrôles. TGlyph est inclus dans de nombreux contrôles prenant en charge l'utilisation des listes d'images.

Les contrôles TGlyph ont la propriété AutoHide. AutoHide définit que le contrôle TGlyph lui-même gère la valeur de la propriété Visible :

  • Durant l'exécution de l'application, lorsque AutoHide est défini sur True, Visible vaut True si le contrôle contient des graphiques (BitmapExists vaut True). Sinon, Visible vaut False. Si le code de l'application essaie de définir une nouvelle valeur sur Visible, cette valeur est ignorée. La valeur Visible a une signification pour la propriété Align lorsque Align ne vaut pas None. Alors si Visible vaut True, un contrôle visible vide dessine l'espace vide occupé par le contrôle. Si Visible vaut False, aucun contrôle invisible vide ne dessine l'espace vide.
  • En mode conception, lorsque AutoHide vaut True, Visible vaut toujours True et est inaccessible.

Les nouvelles propriétés Images et ImageIndex apparaissent dans de nombreux contrôles graphiques (boutons, menus, listes et autres) et actions. Notez que pour les composants fournissant des listes d'éléments, l'inspecteur d'objets affiche seulement la propriété Images. Alors que pour les éléments de ces listes l'inspecteur d'objets affiche seulement la propriété ImageIndex. Notez que la propriété Images de chacun des éléments d'un contrôle de liste a la même valeur que Images dans le contrôle de liste. C'est-à-dire que tous les éléments de menu utilisent toujours la même collection Images, définie dans la propriété Images du menu.

Certains contrôles dotés des propriétés Images et ImageIndex peuvent également avoir la propriété Bitmap, qui peut également référencer une image. Si les propriétés Images et ImageIndex pointent vers une image existante, cette image est dessinée. Si ImageIndex ne pointe pas vers une image existante, le contrôle dessine l'image référencée par Bitmap. Notez que l'image référencée à partir de Bitmap n'est pas utilisée, est est simplement ignorée. Elle n'est pas supprimée automatiquement afin d'éviter la perte de données, par exemple, si vous définissez occasionnellement ImageIndex pour référencer une image non existante. Vous pouvez supprimer cette référence à l'image manuellement, en modifiant la propriété Bitmap.

Structure du niveau supérieur de TImageList

En général, une application FireMonkey ne connaît pas la taille requise d'une image à dessiner. Cela dépend d'un contrôle particulier, du style de contrôle et de l'échelle de la scène (et cette échelle peut seulement être égale à 1, 1.5, 2), laquelle dépend elle-même de l'ordinateur ou du périphérique mobile particulier. Par conséquent, les images sont souvent mises à l'échelle pour s'adapter aux limites souhaitées. Nous avons donc introduit la classe TMultiResBitmap. Les bitmaps multi-résolutions stockent plusieurs variantes de la même image optimisée pour différentes tailles. Cela minimise la perte de qualité lors de la mise à l'échelle des images. A l'étape suivante, nous avons introduit les listes d'images TImageList. Les objets TImageList stockent des collections d'images TMultiResBitmap. Chacun de ces bitmaps multi-résolutions est un ensemble de plusieurs variantes de la même image avec différentes tailles.

Nous devons examiner la structure TImageList du composant pour comprendre la signification et la fonctionnalité des éléments dans l'éditeur de liste d'images.

Chaque composant TImageList contient deux collections d'images :

  • La collection Source contient les données graphiques source. Ces données sont utilisées pour produire des images dans la collection Destination.
  • La collection Destination contient les données requises pour former les images à dessiner comme images de la collection TImageList.

Prenons le cas de l'exemple ImageList représenté dans la vue Structure ci-dessous, vous pouvez voir la structure ImageList1 comme suit :

Vue Structure dans l'éditeur de liste d'images

Dans cette figure, vous pouvez voir que chaque image de la collection Source a :

  • Un nom unique (sans distinction minuscules/majuscules) (dans chaque collection TImageList). Par exemple, l'image 0 a le nom Stop, l'image 1 a le nom TImageList et l'image 2 a le nom folder.
  • La propriété MultiResBitmap. A son tour, chaque élément dans une collection MultiResBitmap représente une variante de la même image avec une taille particulière (échelle). Par exemple, la collection MultiResBitmap de l'image folder contient 5 bitmaps pour les échelles 1.0, 2.0, 1.5, 3.0 et 16.0.

Dans cette figure, vous voyez aussi que chaque élément de la collection Destination peut inclure plusieurs couches, qui sont incluses dans la collection Layers. Par exemple, l'image 3 se compose de deux couches : la couche 0 contenant le bitmap multi-résolution folder et la couche 1 contenant le bitmap multi-résolution delete. Chaque couche contient le nom du bitmap multi-résolution source et les coordonnées d'une section de ce bitmap (toujours à l'échelle 1). Cette section du bitmap est dessinée en générant l'image. Pendant la génération d'une image, FireMonkey commence par dessiner le bitmap multi-résolution à partir de la couche 0. Puis, le bitmap multi-résolution de la couche 1 est dessiné sur l'image obtenue, le bitmap multi-résolution de la couche 2 est dessiné sur l'image obtenue, et ainsi de suite. Nous allons vous montrer cela plus en détail dans la section Volet Image sélectionnée. Si, dans une couche, un bitmap multi-résolution comporte des bitmaps ayant plusieurs échelles, alors le bitmap ayant l'échelle la plus appropriée est utilisé. L'échelle est sélectionnée en fonction de la taille requise de l'image prête à l'emploi et de l'échelle de la scène.

En connaissant la structure TImageList, on peut former des parties de l'instance complète de TImageList à l'exécution. L'exemple ImageList contient l'exemple d'un tel code.

Pour modifier une collection TImageList dans l'EDI, vous pouvez utiliser la vue Structure et l'inspecteur d'objets. Toutefois, nous fournissons l'éditeur de liste d'images spécialisé, qui est bien plus pratique pour gérer un contenu de collections TImageList.

Différences avec l'implémentation de TImageList dans la VCL

Dans la VCL, une liste d'images Vcl.Controls.TImageList est une collection d'images ayant la même taille fixe. Cela crée des problèmes lorsque votre application tente de dessiner des images avec différentes échelles. Pour dessiner des images avec une échelle différente dans des applications VCL, nous devons créer plusieurs objets TImageList. Chaque objet TImageList contient une collection spéciale d'images pour une taille particulière. Dans tous les objets TImageList de ce type, les mêmes images devraient avoir les mêmes numéros (Index). Une application VCL peut seulement dessiner des images ayant ces échelles. Dans les applications VCL, il est difficile de changer certaines images pendant l'exécution.

Utilisation de l'éditeur de liste d'images

Vous pouvez regarder la vidéo présentant l'utilisation de l'éditeur de liste d'images pour créer et modifier des listes d'images (EN). Cette vidéo montre des fonctionnalités avancées et essentielles de l'éditeur de liste d'images.

Nous décrivons les propriétés de l'éditeur de liste d'images en utilisant l'exemple ImageList, qui fournit un cas d'utilisation de la liste d'images. Chargez le projet ImageListDemo.dproj puis, dans le Gestionnaire de projets, double-cliquez sur le module UnitDataModule.dfm. Dans le Concepteur de fiches, double-cliquez sur l'icône ImageList1. L'éditeur de liste d'images s'ouvre avec le composant ImageList1. L'éditeur de liste d'images contient trois volets : Liste d'images, Sources des images et Image sélectionnée.

Editeur de liste d'images

Volet Liste d'images

Le volet Liste d'images affiche la liste horizontale des images. Chaque image est un aperçu d'une image correspondante dans la collection Destination. Ces images sont affichées dans la propriété ImageIndex de chaque contrôle utilisant cette collection d'images.

Dans le volet Liste d'images, vous pouvez faire glisser les images (à l'aide de la souris) pour changer leur ordre dans la collection d'images ImageList1.

Le bouton Ajouter permet d'ajouter une image à partir d'un fichier. Lorsque vous cliquez sur Ajouter, la boîte de dialogue Ajouter des images s'ouvre. Vous pouvez alors naviguer jusqu'à un fichier d'image. Si la taille d'une image à ajouter est un multiple de la largeur et de la hauteur spécifiées, un message vous demande si l'éditeur de liste d'images doit diviser l'image en plusieurs images. Cela est particulièrement utile pour les bitmaps de la barre d'outils qui sont généralement composés de plusieurs petites images affichées dans un ordre précis et stockées sous la forme d'un bitmap plus grand. L'image ajoutée apparaît en surbrillance dans la liste d'aperçus du volet Liste d'images et s'affiche dans le volet Image sélectionnée. Notez que l'image est ajoutée dans la collection Source et s'affiche dans le volet Sources des images.

En utilisant le bouton Exporter, vous pouvez enregistrer toutes les images de la collection Destination dans un seul fichier graphique. L'image stockée dans ce fichier se compose de fragments contenant toutes les images dans le volet Liste d'images. Tous les fragments ont la même taille définie par la Largeur et la Hauteur spécifiées.

Le bouton Supprimer supprime l'image sélectionnée de la collection Destination. (Notez que Supprimer ne supprime pas l'image correspondante dans la collection Source.)

Le bouton de barre d'outils New.png (Nouvelle image) (dans l'angle supérieur gauche du volet) ajoute une image chargée précédemment (ayant une couche). Si la focalisation est dans le volet Sources des images, l'image sélectionnée est ajoutée. Sinon, une image d'une couche sélectionnée dans le volet Image sélectionnée est ajoutée. L'image ajoutée apparaît en surbrillance dans le volet Liste d'images.

Volet Sources des images

Le volet Sources des images (voir la figure Editeur de liste d'images ci-dessus) affiche toutes les images dans la collection Source de la liste d'images TImageList en cours. Ces images source sont utilisées pour construire des images dans la collection Destination (affichées dans le volet Liste d'images).

Comme nous l'avons déjà mentionné, lorsque vous cliquez sur Supprimer dans le volet Liste d'images, l'image sélectionnée dans la collectionDestination est supprimée. Notez que Supprimer ne supprime pas l'image correspondante dans la collection Source affichée dans le volet Sources des images. Pour supprimer une image de la collection Source, utilisez le bouton de la barre d'outils Action delete.png Supprimer la source.

Les boutons flèches Arrow up.jpg et Arrow down.jpg de la barre d'outils permettent de changer l'ordre des images source en les déplaçant vers le haut ou vers le bas. Vous pouvez utiliser ces flèches à votre convenance.

Cliquez sur le bouton de barre d'outils New.png (Nouvelle source) pour ajouter une nouvelle image dans la collection Source. Lorsque vous cliquez sur ce bouton, le message demandant le nom du nouvel élément source apparaît, puis l'éditeur MultiResBitmap est activé.

Utilisation de l'éditeur MultiResBitmap

Vous pouvez regarder la vidéo présentant l'usage typique de l'éditeur MultiResBitmap (EN).

A l'aide de l'éditeur MultiResBitmap, vous pouvez ajouter plusieurs images optimisées pour différentes échelles :

ImageList de l'éditeur MultiResBitmap

Lors de l'exécution, une application sélectionne l'image ayant l'échelle la plus appropriée.

Comme nous l'avons déjà indiqué, le composant TImageList permet de stocker des listes de très nombreuses petites images. Les images du composant TImageList ont pour objet d'être utilisées comme des icônes dans des contrôles, des menus, des listes, et ainsi de suite.

Si vous avez seulement des fichiers contenant de grandes images, vous pouvez personnaliser leurs tailles pendant l'ajout de ces images dans l'éditeur MultiResBitmap. Avant d'ajouter une grande image à partir d'un fichier, cliquez sur le contrôle Type de taille (SizeKind) et sélectionnez Taille personnalisée dans la liste ouverte. Les zones d'édition Largeur et Hauteur apparaissent, si elles n'étaient pas déjà affichées. Largeur et Hauteur définissent les propriétés Width et Height de l'image ayant la valeur Echelle = 1. Par exemple, si vous chargez une image pour Echelle = 1.5, les valeurs Largeur et Hauteur spécifiées sont multipliées par 1.5. Pour charger une image pour une Echelle particulière, cliquez sur le bouton Fill All From File.png. Pour charger une image pour toutes les échelles, cliquez sur le bouton de barre d'outils Fill All From File.png Tout remplir depuis le fichier dans la barre d'outils de l'éditeur MultiResBitmap.

Notez que l'utilisation de l'option Taille personnalisée ne change pas l'image dans un fichier source. L'utilisation de Taille personnalisée change seulement la taille de l'image stockée dans le fichier .fmx ou .dfm.

Notez que les informations de conception utilisées par l'éditeur MultiResBitmap incluent les informations relatives à Couleur transparente, Type de taille, Largeur, Hauteur, ainsi que les noms des fichiers source des images. Ces propriétés ne sont pas publiées et sont utilisées uniquement à la conception. Une fois terminée la modification du bitmap multi-résolution, ces propriétés peuvent être retirées du fichier .fmx ou .dfm en utilisant le bouton de barre d'outils Clear design time info and close.png (Terminer). Lorsque vous appuyez sur Clear design time info and close.png dans l'éditeur MultiResBitmap, les informations de conception sont effacées seulement dans le bitmap multi-résolution qui est en cours de modification dans l'éditeur MultiResBitmap. Lorsque vous appuyez sur Clear design time info and close.png dans l'éditeur de liste d'images, les informations de conception sont effacées pour toutes les images dans la liste d'images en cours.

Volet Image sélectionnée

Le volet Image sélectionnée affiche (voir la figure Editeur de liste d'images ci-dessus) des informations détaillées sur l'image sélectionnée dans le volet Liste d'images. Comme nous le savons, Liste d'images affiche des aperçus des images dans la collection Destination.

Comme nous l'avons déjà mentionné dans la section Structure de TImageList (voir la figure Vue Structure ci-dessus), chaque image dans la collection Destination peut contenir plusieurs couches. Chaque couche affiche un nom d'une image de la collection Source et le bitmap multi-résolution correspondant. Chaque couche contient également les coordonnées d'une section de ce bitmap multi-résolution (toujours à l'échelle 1, indépendamment de l'échelle du bitmap à utiliser). Seule cette section du bitmap multi-résolution est dessinée dans l'image prête à l'emploi.

Généralement, chaque image contient une seule couche. Toutefois, vous souhaiterez dans certains cas utiliser plusieurs couches pour former une image composée. Par exemple, il peut être pratique d'utiliser une couche distincte contenant une image représentant 'un texte barré' ou une 'loupe'. Cette couche peut alors être placée sur une couche contenant une autre image. Par exemple, l'image dans la couche peut être dessinée sur une couche contenant une image 'dossier' ou 'enveloppe'. Les deux couches peuvent alors former une image combinée, telle qu'une image 'dossier barré' ou 'loupe sur enveloppe'.

Pendant la génération d'une image, FireMonkey commence par dessiner le bitmap multi-résolution à partir de la couche 0. Puis, le bitmap multi-résolution de la couche 1 est dessiné sur l'image obtenue, le bitmap multi-résolution de la couche 2 est dessiné sur l'image combinée obtenue, et ainsi de suite. Si une image avec le nom spécifié dans une couche n'existe pas ou si le secteur spécifié est en dehors de l'image, alors la couche ne dessine rien et aucune exception n'est déclenchée. Si, dans une couche, un bitmap multi-résolution a des bitmaps avec plusieurs échelles, alors le bitmap ayant l'échelle la plus appropriée est utilisé. L'échelle est sélectionnée en fonction de la taille requise de l'image prête à l'emploi et de l'échelle de la scène.

Nous allons vous présenter ces fonctionnalités en utilisant des images de l'exemple ImageList. Dans le volet Liste d'images (voir Utilisation de l'éditeur de liste d'images ci-dessus), sélectionnez l'image ayant ImageIndex = 3. Il s'agit du 'dossier barré'. Le volet Image sélectionnée affiche les 2 couches suivantes :

Volet Image sélectionnée pour le dossier barré

Comparez ceci avec la représentation de l'image Destination ayant ImageIndex = 3 dans la vue Structure :

Vue Structure pour le dossier barré

Dans cette figure, nous voyons que l'image folder est dans la couche 0 et que l'image delete est dans la couche 1. Dans le volet Liste d'images, vous voyez que ces 2 couches produisent l'image de destination 'dossier barré' suivante :

Dossier barré

Vous voyez que l'image delete dans la couche 1 est dessinée sur l'image folder à partir de la couche 0.

Dans le volet d'une couche, les zones d'édition Gauche, Haut, Largeur et Hauteur spécifient les coordonnées d'une section du bitmap multi-résolution stockée dans la couche. Vous pouvez voir ces coordonnées dans la figure Volet Image sélectionnée pour le dossier barré en tant que (0,0,16,16) pour l'image delete. Définissons Gauche sur 4 et Haut sur 4 pour l'image delete. Cliquez sur Appliquer. A présent, dans la vue Structure vous voyez les coordonnées (4,4,20,20) de la section pour l'image delete. Dans le volet Liste d'images, l'image de destination 'dossier barré' a changé. L'image 'dossier barré' est décalée en haut à gauche :

Le dossier barré est déplacé

Pour présenter l'utilisation des coordonnées de la section d'un bitmap multi-résolution, double-cliquez sur l'image 'dossier barré'. L'éditeur MultiResBitmap s'ouvre :

Section à afficher dans l'éditeur MultiResBitmap

Cette figure montre quelle section de l'image 'dossier barré' est dessinée dans la couche. Cliquez dans le rectangle de sélection qui spécifie la 'section à afficher'. Essayez de redimensionner le rectangle de sélection. Essayez de déplacer le rectangle de sélection et de voir les changements correspondants des propriétés Gauche, Haut, Largeur et Hauteur du rectangle de sélection (dans la couche au sein de Image sélectionnée) ainsi que les changements de l'image d'aperçu dans le volet Liste d'images.

La fonctionnalité des boutons de la barre d'outils dans le volet Image sélectionnée est plutôt évidente. New.png -- ajoute une nouvelle couche dans le volet Image sélectionnée. Action delete.png -- supprime la couche sélectionnée du voletImage sélectionnée. Arrow up.jpg et Arrow down.jpg permettent de changer l'ordre des couches en déplaçant la couche sélectionnée vers le haut et vers le bas. Cela peut être utile, car l'image ayant le numéro le plus élevé dans une couche est dessinée par-dessus les images dessinées par les couches précédentes.

Classes de base de TImageList

Les informations sur les fonctions et fonctionnalités de base des classes de listes d'images peuvent être utiles pour ceux qui souhaitent développer des composants personnalisés en utilisant des listes d'images.

Unité System.ImageList

A partir de la version XE8, RAD Studio fournit la nouvelle unité RTL System.ImageList. System.ImageList contient le code commun de la VCL et de FireMonkey implémentant les fonctionnalités des listes d'images les plus basiques et indépendantes du périphérique. System.ImageList contient le code prenant en charge l'interaction entre les images dans une liste d'images et leur utilisation dans des composants (contrôles, éléments de menu, et ainsi de suite).

L'unité System.ImageList définit les classes TBaseImageList et TImageLink.

Classe TBaseImageList

La classe TBaseImageList fournit les méthodes et les propriétés gérant les interactions entre une liste d'images et tous les composants GUI à l'aide d'images de la liste d'images. A partir de la version XE8 de RAD Studio, les classes FMX.ImgList.TCustomImageList et Vcl.ImgList.TCustomImageList héritent de cette classe TBaseImageList.

Classe TImageLink

Un objet liste d'images TBaseImageList utilise des objets TImageLink pour envoyer aux composants utilisant l'objet liste d'images des notifications concernant des changements survenus dans cet objet liste d'images.

Lorsque des changements surviennent au niveau des propriétés ImageIndex ou Images, l'objet TImageLink appelle la méthode Change virtuelle. Rappelez-vous que toute modification dans TBaseImageList entraîne le changement de Images.

Pour que votre composant soit en mesure de fournir une réaction adéquate en cas de changement dans une liste d'images, il doit contenir une instance du descendant TImageLink. Ce descendant TImageLink doit avoir des propriétés Images et ImageIndex correctes et doit redéfinir la méthode Change, ou bien le gestionnaire d'événement OnChange doit être défini.

TBaseImageList contient la propriété de tableau Links qui contient elle-même les instances de TImageLink. Lorsque vous définissez la propriété TImageLink.Images sur un composant, cette liste d'images s'ajoute à ce tableau Links. Après tout changement des propriétés Images ou ImageIndex, les descendants de TBaseImageList prennent séquentiellement chaque objet lien d'image dans le tableau Links et appellent Change pour tous ou certains de ces liens d'images (composants).

Propriété TImageLink.IgnoreIndex

Si la propriété IgnoreIndex vaut True, Change n'est pas exécutée en cas de changement d'une image ou d'un ordre d'images dans une liste d'images TBaseImageList. Généralement, les notifications arrivent en cas de changement d'une image avec un certain index. Le fait de définir IgnoreIndex sur True supprime de telles notifications. Cette propriété peut être utilisée lorsqu'une application a besoin d'afficher la liste d'images complète, par exemple, dans une fenêtre d'éditeur.

Propriété TImageLink.IgnoreImages

Si la propriété IgnoreImages vaut True, Change n'est pas exécutée en cas de changement de la valeur de Images. La propriété est utilisée pour la compatibilité avec les classes VCL héritant des classes de System.ImageList.

Unité FMX.ImgList

L'unité FMX.ImgList définit les classes FireMonkey de base implémentant les listes d'images FireMonkey.

Classe FMX.ImgList.TCustomImageList

Le composant FMX.ImgList.TCustomImageList implémente la fonctionnalité principale des listes d'images FireMonkey. Généralement, FMX.ImgList.TImageList ne diffère de la classe FMX.ImgList.TCustomImageList que par la redéclaration de certaines propriétés comme publiées. Dans le cas de FMX.ImgList.TImageList, il s'agit des propriétés publiées suivantes : Source, Destination, OnChanged et OnChange.

Propriété TCustomImageList.Dormant

La propriété Dormant vaut True si tous les bitmaps multi-résolutions dans la collection Source ont leurs propriétés Dormant définies sur True.

Propriété TCustomImageList.CacheSize

La propriété CacheSize indique le nombre maximum d'images pouvant être stockées dans le cache interne de l'objet TCustomImageList en cours.

Le dessin de chaque image s'effectue en plusieurs étapes plutôt gourmandes en ressources. Pour éviter de mettre à l'échelle et de dessiner plusieurs couches pour afficher la même image dans chacun des multiples contrôles, l'image générée est placée dans le tableau dans le cache interne, puis l'image prête est récupérée à partir de ce tableau en cache. La nouvelle image générée est ajoutée à la fin de ce tableau en cache, décalant ainsi toutes les images existantes au début du tableau. Si le nombre d'images à stocker dans le tableau en cache excède le nombre d'images CacheSize spécifié, l'image la plus ancienne est supprimée du cache. Il est évident que plus le nombre d'images CacheSize est élevé, plus la vitesse de traitement augmente et plus la quantité de mémoire utilisée augmente. Le nombre maximum d'images par défaut à stocker dans le tableau en cache est 8 ; le nombre minimum est 1.

Méthode TCustomImageList.ClearCache

ClearCache retire l'image spécifiée par le numéro Index du tableau dans le cache interne. Le cache peut stocker plusieurs images avec le même numéro mais avec différentes tailles. Si Index vaut -1 (valeur par défaut), toutes les images sont supprimées du cache (le cache est effacé). Généralement ClearCache est automatiquement appelée en cas de modification de l'objet TImageList.

Méthode TCustomImageList.BitmapExists

La méthode BitmapExists renvoie True, si une image avec le numéro spécifié existe et contient un bitmap. C'est-à-dire, si l'image spécifiée contient au moins une couche contenant le nom d'une image source existante ayant un rectangle à dessiner n'ayant aucune intersection avec le rectangle de l'image.

Une image non existante s'affiche sous la forme d'un rectangle vide formé de lignes discontinues dans l'éditeur de liste d'images. Voir le numéro d'image 9 dans le volet Liste d'images dans la figure Editeur de liste d'images ci-dessus. Si le rectangle à dessiner contient des données graphiques, mais que tous ces graphiques sont transparents (voir Couleur transparente), la méthode BitmapExists renvoie True, mais cette couche ne dessine pas de graphiques. BitmapExists est utilisé dans la classe TGlyph pour définir la propriété Visible lorsque AutoHide vaut True.

Méthode TCustomImageList.Bitmap

La méthode Bitmap renvoie l'objet TBitmap stocké dans le cache correspondant à l'image spécifiée par Index et ayant la taille Size spécifiée.

Si l'image spécifiée par Index et ayant Size n'existe pas dans le cache, Bitmap essaie de créer une image appropriée et de l'ajouter dans le cache. Si une image Index n'existe pas dans la collection Source ou si Bitmap ne peut pas créer un bitmap ayant la valeur Size spécifiée ou ne peut pas l'ajouter dans le cache, Bitmap renvoie nil.

Etant donné que les images dans le cache sont créées et détruites par des fonctionnalités TCustomImageList internes, vous ne devez pas explicitement détruire l'objet TBitmap renvoyé, stocké dans le cache, ni tenter de stocker une référence à cet objet.

Si vous devez simplement dessiner une image de la liste TCustomImageList, utilisez la méthode Draw. Si vous avez vraiment besoin de stocker l'objet TBitmap obtenu pour un usage futur, vous devez créer un autre objet TBitmap et utiliser Assign pour créer une copie de l'objet TBitmap obtenu.

Méthode TCustomImageList.BitmapItemByName

La méthode BitmapItemByName renvoie True si elle trouve une image ayant la valeur Name spécifiée dans la collection Source.

Si BitmapItemByName renvoie True, Item renvoie le bitmap trouvé pour une échelle plus appropriée de 1, et Size renvoie la taille du bitmap renvoyé. Si BitmapItemByName renvoie False, Item et Size ne sont pas changés.

Méthode TCustomImageList.UpdateImmediately

La méthode UpdateImmediately initie un nouveau dessin immédiat de tous les composants utilisant cette liste d'images.

En cas de modification d'une image, tous les composants utilisant cette image doivent recevoir des notifications pour mettre à jour leur image. Par défaut, pour éviter plusieurs nouveaux dessins pendant la reformation d'une liste d'images, de telles notifications sont envoyées très peu de temps après les changements. S'il y a plusieurs changements durant cette période, seule une notification est envoyée et les contrôles ne sont redessinés qu'une seule fois.

Propriété TCustomImageList.Source

La propriété Source conserve la référence à la collection TSourceCollection contenant les bitmaps multi-résolutions source de TCustomSourceItem. Les collections source sont créées par la méthode CreateSource. Vous pouvez redéfinir cette méthode pour créer des collections de votre propre type. La méthode importante des collections source TSourceCollection est IndexOf, qui retourne l'index de l'image dans les collections source correspondant à la valeur Name spécifiée. Si aucune image n'est trouvée, nil est renvoyé.

Classe TCustomSourceItem

La classe TCustomSourceItem définit des éléments des collections source TSourceCollection. Chaque objet TCustomSourceItem a un nom unique (sans distinction majuscules/minuscules) de l'élément image dans la collection Source et une propriété MultiResBitmap contenant un bitmap multi-résolution conservant l'ensemble des images de même forme pour différentes échelles.

Propriété TCustomImageList.Destination

La propriété Destination conserve la référence à la collection TDestinationCollection contenant des éléments TCustomDestinationItem. Les éléments de destination contiennent les informations requises pour préparer les images à dessiner. Les collections de destination sont créées par CreateDestination.

Classe TCustomDestinationItem

Les objets TCustomDestinationItem sont des éléments des collections TDestinationCollection. Chaque élément TCustomDestinationItem contient la collection Layers d'éléments TLayer. Layers est créée avec CreateLayers. La fonction LayersCount renvoie le nombre de couches non vides. Notez la différence avec la propriété TLayers.Count, qui conserve le nombre total de couches dans la collection Layer.

Classe TLayers

La collection TLayers contient les couches TLayer. Pendant la génération d'images prêtes à l'emploi, les bitmaps ayant les échelles les plus appropriées de toutes les couches visibles sont séquentiellement dessinés à partir de la couche 0 et jusqu'à la dernière couche Count.

Classe TLayer

La couche TLayer contient des informations sur une image source, qui est utilisée pendant le dessin d'une image prête à l'emploi.

Propriété TLayer.MultiResBitmap

La propriété MultiResBitmap conserve un bitmap multi-résolution de la collection Source.

Propriété TLayer.Name

La propriété Name contient le nom (sans distinction majuscules/minuscules) d'une image de la collection Source. La fonction BitmapItemByName renvoie le bitmap multi-résolution ayant le nom spécifié dans la collection Source.

Propriété TLayer.SourceRect

La propriété SourceRect conserve les coordonnées d'une section de ce bitmap multi-résolution (toujours à l'échelle 1, indépendamment de l'échelle du bitmap à utiliser). Seule cette section du bitmap multi-résolution est dessinée dans l'image prête à l'emploi.

Exemple de code FMX.TImageList

Vous pouvez voir la vidéo présentant les fonctionnalités programmées dans 'l'exemple FMX.ImageList' (EN).

Nous y présentons les fragments de code typiques - issus de l'exemple FMX.ImageList fournissant l'exemple de l'utilisation de la liste d'images - utilisés pour programmer les opérations standard des listes d'images.

Ouvrez le projet ImageListDemo.dproj, tel qu'il est décrit dans l'exemple FMX.ImageList. Activez le Concepteur de fiches avec le module UnitMain et ouvrez l'onglet Bitmap and Image. Cet onglet contient plusieurs contrôles utilisant des images de la liste d'images. Nous traitons ici de la fonctionnalité d'implémentation du code des boutons Add New Source et Update Text et des boutons flèches Droite et Gauche dessinant l'image suivante ou précédente - à partir de la liste d'images ImageList1 - sur le libellé None de l'onglet None. Le code gérant les boutons flèches Droite et Gauche montre comment dessiner une image à partir d'une liste d'images sur la surface de votre contrôle personnalisé.

Pour ouvrir le code gérant un contrôle dans l'éditeur de code, double-cliquez simplement sur ce contrôle dans le Concepteur de fiches.

Gestionnaire d'événement du bouton 'Add New Source'

Double-cliquez sur le bouton Add New Source dans le Concepteur de fiches. L'éditeur de code affiche l'implémentation ActnAddSourceExecute de la méthode. ActnAddSourceExecute est le gestionnaire d'événement OnClick du bouton Add New Source. ActnAddSourceExecute appelle AddSourceToItem(9). L'élément principal de ActnAddSourceExecute est la méthode interne

DrawPicture(Canvas: TCanvas; R: TRectF; Scale: Single)

. Cette méthode dessine simplement une image dans le Canvas spécifié. Un autre code de AddSourceToItem(9) prépare les paramètres pour appeler DrawPicture. La méthode AddSourceToItem(9) assigne la valeur de paramètre spécifiée 9 au ImageIndex de la nouvelle image ajoutée dans ImageList1. C'est-à-dire, ImageIndex=9. Au début, AddSourceToItem vérifie si l'image - dans la collection Destination - ayant ImageIndex=9 a, au moins, une couche. Sinon, créez la couche 0. Si la couche 0 contient une image, cette image est stockée dans la variable SourceName :

SourceName := Layer.Name;

BitmapItemByName est appelée

MainDataModule.ImageList1.BitmapItemByName(SourceName, Item, Size)

pour extraire un élément correspondant au nom SourceName spécifié à partir de la collection Source. Si cela réussit, nous considérons que l'image est déjà ajoutée et vous n'avez rien à faire de plus. Sinon, ajoutez une nouvelle image dans la collection Source. Si la couche existe et contient le nom SourceName, le nom SourceName est assigné à l'image ajoutée. Sinon, le nom par défaut est utilisé.

A présent, créez cycliquement plusieurs images pour différentes échelles. Ajoutez un nouvel élément dans TMultiResBitmap. Il obtient sa valeur par défaut :

S := Item.Scale;

En utilisant les valeurs S et SourceRect de la couche, calculez la taille de l'image Source :

Size.cx := Round(Layer.SourceRect.Width * S);

Puis remplissez cette image en utilisant la couleur transparente

Item.Bitmap.Clear(TAlphaColorRec.Null);

et dessinez une image :

DrawPicture(Item.Bitmap.Canvas, R, S);
Remarque : Ouvrez l'unité UnitDataModule dans le Concepteur de fiches et double-cliquez sur l'image ImageList1. Dans le volet Liste d'images, vous voyez que l'image ayant ImageIndex=9 est vide.

Donc, avec l'implémentation en cours, le fait de cliquer sur Add New Source ajoute la nouvelle image ayant ImageIndex=9 dans la liste d'images ImageList1.

Comment regarder la fonctionnalité du bouton 'Add New Source' :

  1. Lisez comment utiliser l'exemple FMX.ImageList.
  2. Dans l'application Demo of images, sélectionnez l'onglet Bitmap and Image.
  3. Cliquez à plusieurs reprises sur le bouton flèche Droite.
    Vous voyez les images de la liste d'images ImageList1 être dessinées séquentiellement sur le libellé None de l'onglet None.
  4. Lorsque vous cliquez sur le bouton flèche Droite pour la neuvième fois, le texte dans le libellé devient Label1 :
Images : 'ImageList1': Counts 11
ImageIndex: 9; Width 16; Height 16
et l'image vide est dessinée sur le libellé None (aucune image n'est dessinée).
  1. Dans l'onglet Bitmap and Image, cliquez sur Add New Source. L'image ayant ImageIndex=9 est ajoutée dans ImageList1.
  2. Vous voyez que l'image ajoutée apparaît sur le libellé None.

Gestionnaire d'événement du bouton 'Update text'

Double-cliquez sur le bouton Update Text dans le Concepteur de fiches. L'éditeur de code affiche l'implémentation ActnUpdateTextExecute de la méthode. ActnUpdateTextExecute est le gestionnaire d'événement OnClick du bouton Update Text.

Le texte à dessiner est obtenu à partir du champ d'entier FNumber qui est converti dans la représentation chaîne FNumber.ToString. Chaque clic Update Text augmente de Inc(FNumber) la valeur de ce champ.

ActnUpdateTextExecute appelle

DrawTextOnLayer(8,FNumber.ToString)

Ici, le premier paramètre 8 spécifie l'index de l'image dans la collection Destination de la liste d'images ImageList1 qui doit être modifiée.

Remarque : Ouvrez l'unité UnitDataModule dans le Concepteur de fiches et double-cliquez sur l'image ImageList1. Dans le volet Liste d'images, cliquez sur l'image ayant ImageIndex=8. Dans le volet Image sélectionnée, vous voyez que cette image contient deux couches. La couche 0 est vide et la couche 1 contient le TMultiResBitmap identifié par le nom mail et affichant une image d'enveloppe :
Image 8

Le deuxième paramètre FNumber.ToString spécifie le texte à dessiner.

DrawTextOnLayer est plutôt similaire à DrawPicture. Au début, DrawTextOnLayer vérifie si l'image - dans la collection Destination - ayant ImageIndex=8 a, au moins, une couche. Puis, il vérifie si la couche supérieure contient une image. Ensuite cette image est stockée dans la variable SourceName :

SourceName := Layer.Name;

BitmapItemByName est appelée

MainDataModule.ImageList1.BitmapItemByName(SourceName, Item, Size)

pour extraire un élément correspondant au nom SourceName spécifié à partir de la collection Source.

Si BitmapItemByName n'extrait pas un élément correspondant au nom SourceName, nous ajoutons un nouvel élément Source :

NewSource := MainDataModule.ImageList1.Source.Add;

Assignez-lui le nom SourceName :

NewSource.Name := SourceName;

Essaie d'obtenir Item :

Item := NewSource.MultiResBitmap.ItemByScale(1, False, True);

Si Item n'existe pas, ajoutez un nouvel élément à la collection MultiResBitmap :

Item := NewSource.MultiResBitmap.Add;

et définissez sa taille :

Item.Bitmap.SetSize(Size.cx, Size.cy);

Selon

Size.cx := Round(Layer.SourceRect.Rect.Width);
Size.cy := Round(Layer.SourceRect.Rect.Height);

Suite à cela ou si BitmapItemByName réussit, DrawTextOnLayer dessine le Text (égal à FNumber.ToString) sur l'image obtenue :

Item.Bitmap.Canvas.FillText(
TRectF.Create(1,0,Size.cx - 1,Size.cy div 2),
Text, False, 1, [], TTextAlign.Center, TTextAlign.Center);

Donc, avec l'implémentation en cours, le fait de cliquer sur Update Text dessine un numéro sur l'image ayant ImageIndex=8 dans la liste d'images ImageList1. Chaque nouveau clic augmente de 1 le numéro dessiné.

Comment regarder la fonctionnalité du bouton 'Update Text' :

  1. Dans l'application Demo of images, sélectionnez l'onglet Bitmap and Image.
  2. Cliquez à plusieurs reprises sur le bouton flèche Droite.
    Vous voyez les images de la liste d'images ImageList1 être dessinées séquentiellement sur le libellé None de l'onglet None et dans le contrôle Glyph1.
  3. Lorsque vous cliquez sur le bouton flèche Droite pour la huitième fois, l'image d'enveloppe ayant ImageIndex=8 est dessinée.
  4. Dans l'image suivante, vous voyez que la chaîne contenant 4 est dessinée sur l'image dans le libellé None et dans le contrôle Glyph1.
Enveloppe avec un 4 dessiné dessus

Utilisation des listes d'images dans vos contrôles

Nous expliquons ici comment dessiner une image à partir d'une liste d'images sur la surface de vos propres contrôles. Vous pouvez utiliser des astuces similaires pour créer vos propres contrôles en utilisant des images des listes d'images.

Cet exemple montre comment dessiner des images à partir de la liste d'images ImageList1 sur la surface du contrôle du quatrième onglet par-dessus le libellé None. Pour le voir, cliquez à plusieurs reprises sur les boutons flèches Droite ou Gauche. Vous voyez les images de la liste d'images ImageList1 être dessinées séquentiellement sur le libellé None.

Fonctionnement du dessin des images

Dans le constructeur TMainForm.Create de la fiche, nous créons le champ FImageLink du type TImageLink. Ensuite

FImageLink.Images := MainDataModule.ImageList1;

assigne la liste d'images ImageList1 à ce champ, puis assigne le gestionnaire d'événement OnImagesChange pour l'événement OnChange. OnImagesChange est exécuté lorsque le programme a besoin de redessiner une image sur un contrôle en utilisant la liste d'images ImageList1. OnImagesChange peut ressembler à ce qui suit :

... TabItem4.Repaint; ...

Le dessin d'une image est effectué à partir du gestionnaire d'événement TabItem4Paint du gestionnaire d'événement OnPaint du contrôle d'onglet TabItem4 :

procedure TMainForm.TabItem4Paint(Sender: TObject; Canvas: TCanvas;
                                  const ARect: TRectF);
var
  R: TRectF;
begin
  R := TRectF.Create(ARect.Right - 22, 4, ARect.Right - 6, 20);
  MainDataModule.ImageList1.Draw(TabItem4.Canvas, R,
                                 Glyph1.ImageIndex);
end;

Ici R est le rectangle - dans le contrôle d'onglet TabItem4 - dans lequel une image est dessinée. Draw dessine l'image Glyph1.ImageIndex dans R sur le canevas TabItem4.Canvas spécifié.

Vous pouvez également créer le descendant de TImageLink dans lequel redéfinir la méthode Change au lieu de créer le gestionnaire d'événement OnChange.

Remarque : N'oubliez pas de libérer le champ FImageLink créé dans le destructeur. Utilisez la méthode DisposeOf.

Si votre contrôle prend en charge l'utilisation des actions, alors il prend aussi probablement en charge l'interface IGlyph. Il est alors préférable de créer un objet TGlyphImageLink, qui appellera la méthode ImagesChanged. Vous devrez ensuite assigner le gestionnaire d'événement OnChange.

Les propriétés ImageIndex et Images de votre contrôle doivent avoir les valeurs correctes. Généralement, les propriétés de style suivant sont utilisées :

property ImageIndex: TImageIndex read GetImageIndex write SetImageIndex
                                  stored ImageIndexStored;

function TMyControl.GetImageIndex: TImageIndex;
begin
  Result := FImageLink.ImageIndex;
end;

procedure TGlyph.SetImageIndex(const Value: TImageIndex);
begin
  FImageLink.ImageIndex := Value;
end;

Voir aussi