I. Apparence prédéterminée▲
Avant de passer à l’apparence dynamique, passons d’abord par une apparence prédéterminée pour voir comment cela se réalise.
En préambule, il me faut peut-être éclaircir un premier point. Il est très facile de créer une liste qui affiche des images à condition d’utiliser la bonne apparence d’élément de liste, et ce, sans une once de code. Comme exemple, cette simple petite réalisation créée au moment du design le prouve :
Cependant, dans cette première image, il s’agit de l’affichage d’une image contenue dans la source des données. Peut-être moins connue est l’utilisation de la propriété de l’élément de liste nommée ImageIndex ; or c’est cette propriété, associée à une liste d’images, que nous allons utiliser.
Voici la liste des étapes à suivre.
Étape 1. Sur une forme, ajoutez un TImageList |
Remplissez-le avec les images désirées, pour les besoins de la démonstration, seules deux suffisent.
Étape 2. Déposez sur la forme un TPrototypeBindSource |
Bien évidemment, il nous faut une source de données. Pour les besoins de la démonstration, je vais utiliser un TProtypeBindSource qui contiendra un champ texte et un champ numérique.
Ajoutez-y un champ texte (LoremIpsum) et un champ numérique entier (UIntegers) :
Gardez en mémoire qu’il s’agit d’une génération aléatoire, la valeur du champ numérique sera donc comprise entre 0 et 200.
Étape 3. Déposez un T ListView |
Modifiez l’apparence (ItemAppearance/ItemAppearance) de façon à ce que l’élément de liste contienne une image. Vous avez le choix entre plusieurs possibilités :
- ImageListItem ;
- ImageListItemBottomDetail ;
- ImageListItemBottomDetailRightButton ;
- ImageListItemRightButton.
Pour ce premier essai, choisissez ImageListItemBottomDetail.
Reliez le composant TImageList au TListView grâce à la propriété ImageList de ce composant.
Étape 4. Liaison des éléments |
Passons maintenant à la partie liaison (LiveBindings) entre la liste et les données.
Pour mémoire, il y a plusieurs possibilités pour appeler le concepteur visuel de liaisons :
En utilisant le menu contextuel du composant (clic droit sur le composant) |
||||
En utilisant le menu situé en bas de l’inspecteur d’objet |
||||
En utilisant le menu de l’EDI |
|
Toutes les versions de Delphi ne proposent pas ce concepteur, c’est néanmoins le cas à partir de la version Tokyo 10.2*.
* hormis sa version Starter
Par glisser-déposer vous allez alors :
- Lier la source de données (Synch ↔ *) ;
- Lier le champ texte (LoremIpsum1 ↔ Item.Text) ;
- Lier le champ numérique (UIntField1 ↔ Item.Detail) * optionnel ;
- Lier le champ numérique (UIntField1 ↔ Item.ImageIndex).
Étape 5. Utilisez CustomFormat |
Bien évidemment, comme il n’y a pas 200 images dans notre TImageList, il y a peu de chances que des icônes soient affichées. Pour pallier cela, j’ai décidé que toute valeur inférieure ou égale à 60 afficherait l’icône 0 de ma liste et que sinon ce serait l’icône 1.
Dans le panneau de structure, sélectionnez l’expression ImageIndex et indiquez dans la propriété CustomFormat la formule IfThen(value<=60
,0
,1
) :
Et voilà, pas besoin d’exécuter le programme, le résultat est déjà visible en mode design !
II. Apparence dynamique▲
Si les apparences prédéterminées couvrent la plupart des besoins, nous sommes restreints à n’afficher que quelques éléments. Depuis Delphi XE7, il est possible de personnaliser l’apparence de vue d’une liste (cf. docwiki), ce qui permet déjà de modifier les apparences prédéterminées, mais surtout, ce qui introduit le mode dynamique.
II-A. Mise en place▲
Repartons de la forme déjà créée au chapitre I, contenant déjà un TImageList.
Étape 1. Ajoutez un nouveau TListView |
Cette fois, sélectionnez une apparence dynamique pour vos éléments de liste (DynamicAppearance) :
N’oubliez pas de renseigner la propriété Images du TListView
Étape 2. Ajoutez des objets |
Sélectionnez la propriété Item de ItemAppearance dans la vue structure. Puis, dans l’inspecteur d’objets, cliquez sur la propriété + et ajoutez successivement un objet texte (TTextObjectAppearance) et un objet image (TImageObjectAppearance).
Voir, par exemple, cet article de Stephen Ball qui montre le processus à suivre.
Étape 3. Basculez en mode conception |
Deux solutions pour le faire :
- soit par le menu situé en bas de l’inspecteur d’objet ;
- soit en utilisant le menu contextuel du composant.
N’hésitez pas à changer le nom de l’objet ajouté (propriété AppearanceObjectName)
Étape 3’. Arrangez la présentation comme bon vous semble |
Étape légèrement plus délicate, ce concepteur étant un peu plus difficile à amadouer.
Quelques conseils :
- prenez bien soin de sélectionner l’élément à modifier dans le panneau structure ;
- jJouez sur la propriété Align avant de tenter de modifier les positions (PlaceOffset) de l’objet.
Étape 4. Liaison des éléments |
Pour plus de facilité et avoir une sorte de WYSIWYG n’oubliez pas de désactiver le mode conception.
Passez sur le concepteur de liaisons (Livebindings) :
- Liez la source de données (Synch ↔ *) ;
- Liez le champ texte (LoremIpsum1 ↔ Item.Text1) ;
- Liez le champ numérique (UIntField1 ↔ Item.Detail) * optionnel.
Que constate-t-on ? Premier « piège » : Item.Text, bien que disponible, ne sera pas affiché. Il faut utiliser Item.Text1. Mais le problème principal, déclencheur de ce tutoriel, c’est qu’il n’y a pas l’élément Item.ImageIndex, celui qui, fort opportunément, nous était proposé chapitre I, lors de la quatrième étape.
II-B. Solution▲
Si, lors du chapitre I, aucun code n’était nécessaire, c’est bien en codant que nous arriverons à résoudre l’objectif. Quel événement utiliser ? OnUpdateObjects du TListView sera le candidat idéal.
Pourquoi OnUpdateObjects et non OnUpdatingObjects ? Parce que je vais utiliser un objet de l’élément de liste et non la source des données pour obtenir la valeur. Je préfère donc attendre que tous les objets soient renseignés avant.
Que nous faut-il ? Accéder à l’objet nommé Image mais aussi à la valeur liée à l’objet Detail.
L’accès à ces deux objets peut se faire en utilisant la fonction FindObject (considérée obsolète et remplacée par FindDrawable) ou FindObjectT<T> (<T> indiquant le type d’objet à obtenir).
À partir du moment où ces deux éléments sont trouvés, il suffira de coder ce qu’a fait l’expression du CustomFormat du chapitre I.
procedure
TFormDemo.ListViewDynamicUpdateObjects(const
Sender: TObject;
const
AItem: TListViewItem);
var
AListItemBitmap : TListItemImage;
AListItemText : TListItemText;
i : Integer
;
begin
AListItemBitmap:=AItem.Objects.FindObjectT<TListItemImage>('Image'
);
AListItemText:=AItem.Objects.FindObjectT<TListItemText>('Detail'
);
if
Assigned(AListItemBitmap) AND
Assigned(AListItemText) then
begin
i:=StrToIntDef(AListItemText.Text,-1
);
if
i<=60
then
AListItemBitmap.ImageIndex:=0
else
AListItemBitmap.ImageIndex:=1
;
end
;
end
;
Bien évidemment, puisqu’il y a du code, le résultat ne sera visible qu’à l’exécution.
III. Pour finir▲
Après avoir révisé ou découvert l’utilisation d’une liste d’images en association à un TListView, nous avons découvert que l’apparence dynamique d’un élément de liste n’offrait pas cette possibilité à moins de passer par un peu de code.
Je tiens à remercier l’équipe rédactionnelle Malick pour ses relances, Alain Weber et Alcatîz pour la relecture technique et escartefigue pour les corrections grammaticales et orthographiques.