Utiliser un renderer (ItemRenderer) dans une liste (dataGrid)
12 juil. 2008
Par Jean Marie Macé - Exemples Flex - Lien permanent
Il peut être intéressant d'avoir un rendu spécifique dans une liste, c'est à dire non seulement un label mais également des images et ajouter quelques fonctionnalités supplémentaire pour chaque items de notre liste.
Pour commencer nous allons peupler notre DataGrid, pour cela nous allons utiliser un fichier XML qui nous servira de source d'informations. Voici ce fichier:
[xml]
<?xml version="1.0" encoding="utf-8"?>
<root>
<photo label="photos une" url="assets/pics1.png"/>
<photo label="photos deux" url="assets/pics2.png"/>
<photo label="photos trois" url="assets/pics3.png"/>
<photo label="photos quatre" url="assets/pics4.png"/>
<photo label="photos cinq" url="assets/pics5.png"/>
</root>
nous allons donc affecter le dataProvider de notre DataGrid au chargement de l'application, pour cela on catch l'événement creationComplete de l'application:
[xml]
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="onCreationComplete()"
layout="absolute"
viewSourceURL="srcview/index.html"
backgroundColor="#62925E">
<mx:Style source="assets/style.css" />
<mx:Script>
<![CDATA[
private function onCreationComplete():void{
dgPhotos.dataProvider = xmlPhotos.photo;
}
]]>
</mx:Script>
<mx:XML id="xmlPhotos" source="data.xml"/>
<mx:Panel title="DataGrid Renderer" width="180" height="250" verticalCenter="0" horizontalCenter="0">
<mx:DataGrid id="dgPhotos" width="100%" >
<mx:columns>
<mx:DataGridColumn itemRenderer="dgRenderer"/>
</mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>
Vous noterez que le DataGridColumn utilise la propriété itemRenderer et celle ci pointe vers mon composant MXML qui fera office de renderer pour chaque élément de la liste.
Ce composant dgRenderer, doit contenir tout ce que l'on souhaite afficher pour chaque item. Dans mon cas, je souhaite afifcher un texte avec un logo à sa droite. Cette image doit afficher une popup lors d'un clique. Voila donc mon composant:
[xml]
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.Label;
import mx.containers.TitleWindow;
import mx.events.CloseEvent;
import mx.core.Application;
import mx.containers.Panel;
import mx.managers.PopUpManager;
private var myPopup:TitleWindow;
private function init():void{
img.addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick(e:MouseEvent):void{
myPopup = new TitleWindow();
myPopup.width = 300;
myPopup.height = 80;
myPopup.showCloseButton = true;
myPopup.title = "Informations";
myPopup.addEventListener(CloseEvent.CLOSE, onPopupClose);
var monText:Label = new Label();
monText.htmlText = "Vous avez cliqué sur l'item:<b>"+txtLabel.text+"</b>";
monText.maxWidth = 300;
myPopup.addChild(monText);
PopUpManager.addPopUp(myPopup, Application.application as DisplayObject, true);
PopUpManager.centerPopUp(myPopup);
}
private function onPopupClose(e:CloseEvent):void{
PopUpManager.removePopUp(myPopup);
}
]]>
</mx:Script>
<mx:Label id="txtLabel" text="{data.@label}" fontWeight="bold" horizontalCenter="0" bottom="0" />
<mx:Image id="img" source="{data.@url}" horizontalCenter="0" verticalCenter="0" width="30" height="30" buttonMode="true"/>
</mx:HBox>
Vous voyez qu'il s'agit simplement de mettre dans un container les éléments dont on a besoin, et d'y ajouter la mécanique avec les listeners. La petite astuce réside dans la façon de lier les données au renderer afin d'afficher correctement celles ci. Ici, dans mon fichier xml chaque tag photo contenait deux attributs, label et url, il suffit donc de lier la propriété text du Label à la data label du xml comme ceci text="{data.@label}" et de même pour la source de l'image source="{data.@url}"
Dernier petit truc, pour faire comprendre à l'utilisateur qu'une action se cache sur le click d'une image, on utilise la propriété buttonMode. Ainsi, automatiquement lors du survol de l'imagel e curseur se transforme en main comme pour un lien hypertext classique
Voila donc le résultat escompté (click droit pour les sources)
Commentaires
Bonjour,
Tomasotoujours aussi utiles ces tutoriaux,
est ce possible, à la place de mettre une image, de faire un lien hypertexte ?
oui c'est tout a fait possible, par exemple en reproduisant le fonctionnement d'un lien hypertexte.
Jim_Nastiqque fait il ce lien ? lors d'un roll-over le texte est souligné et lors d'un click il affiche une autre page. Hors les événements souris sont très facile a capter en ActionScript(MouseEvent.CLICK, MouseEvent.MOUSE_OVER) il suffit ensuite d'utiliser la méthode setStyle sur le texte lors du roll over et utiliser la classe navigateToURL pour ouvirir un lien externe ;)
Merci pour ces explications
Tomasoaurais-tu un exemple ?
Je n'ai pas d'exemple sous la main et pas le temps de t'en donner , mais je t'ai donné toutes les billes pour le faire,c'est franchement pas compliqué ;). Si tu captes(et ça se fait en une ligne) les événements souris t'as fait la moitié du chemin.
Jim_NastiqBonjour,
GarthJe cherche à savoir s'il est possible de passer une variable à un renderer ?
En fait j'ai un datagrid avec un id d'un intervenant rattaché à un client. pour cet id dans le datagrid, j'affiche un combobox avec la liste de tous les intervenants fournie par un service qui se connecte à une base de donnée. Ainsi, par défaut, dans le combo est sélectionné l'intervenant rattaché, mais on peut aller rattacher un autre intervenant si l'on souhaite basculer le client d'un intervenant à un autre.
Mon problème aujourd'hui : pour chaque client (combo), je rappelle le service de chargement et cela est en fait assez long... Si je pouvais appeler 1 fois le service et le ré-utiliser pour tous les combos, ce serait plus rapide !.
Merci de votre aide.
Garth
Bonjour,
Jim_Nastiqcomment utilisez vous le dataProvider du dataGrid? il faut garder à l'esprit que le renderer n'est que du "cosmétique" les informations et l'alimentation ne se joue pas dans un renderer.
Si j'ai bien compris, il vous faut un dataProvider(ArrayCollection) qui soit bien construit avec pour chaque item un id et une autre ArrayCollection(celle qui fera office de dataProvider pour la combo de votre renderer.
donc dans le composant parent je construirais mon ArrayCollection comme il faut pour l'affecter au dataProvider du DataGrid puis dans le renderer le dataProvider de ma combobox serait qq chose du genre data.monArray, en supposant que monArray est le nom de l'ArrayCollection qui est imbriquée dans l'ArrayCollection du dataprovider du dataGrid (celle qui contient la liste des intervenant quoi :) )
si je n'ai pas été clair(fort problable) n'hésitez pas pour des précisions ;)
Il faut donc "insérer" le dataprovider du combo dans le dataprovider de la datagrid parent ?
Garthoui si l'on peut dire, ainsi, cela évite l'appel au service pour chaque combo, il n'est fait qu'une fois lors de la création de l'arraycollection qui sert de dataProvider à la dataGrid ;)
Jim_NastiqCa m'a l'air complexe !
GarthN'y a t il pas un autre moyen que le renderer pour afficher un combo dans une data grid ?
non ce n'est pas vraiment complexe a mettre en place. il suffit de bien préparer les donnée avant l'affectation au dataProvider du dataGrid ;)
Jim_NastiqBon j'arrive un peu après la bataille, mais ça servira quand meme, dans le cas de Garth, il peut récupérer son ArrayCollection depuis l'item renderer avec le mot clé outerDocument.
TisiÇa donne quelque chose du style:
outerDocument.myAc;
il faut juste que l'ArrayCollection soit public de cette maniere l'item renderer peut le recuperer dans l'application parente avec le mot clé.
Bonjour,
Vraiment super ce tuto, simple et clair ;-)
Mais dis moi, comment mettre un headerText au différentes colonnes?
Merci encore pour ce tuto ^_^
lepotierSalut,
tout simplement en ajoutant la propriété headerText sur le tag DataGridColumn (Renderer.mxml) :
<mx:DataGridColumn itemRenderer="dgRenderer" headerText="Ton Texte"/>
Jim_NastiqBonjour,
Olun08J'ai fait la même chose que toi en mettant l'image avant le texte et je souhaiterait que le texte se mette automatiquement sur plusieurs ligne si la la colonne de la datagrid n'est pas assez large.
Aurais tu une idée?
Merci d'avance.
Olun
J'utilise la classe Label qui ne gère pas le retour à la ligne. Regardes les classes Text, TextArea
Jim_NastiqMerci pour ce tuto!
Je voudrais utiliser le datagrid pour afficher une galerie d'images, en lignes et colonnes donc. Comment pourrais-je spécifier le nombre de colonnes?
Merci d'avance
andjuah c'est bon j'ai trouvé! il faut utiliser un TILELIST!
andjuMerci pour ce tuto.
J'aimerais savoir comment peut on s'y prendre pour que dans le cas d'une datagrid ayant plusieurs colonnes, un evenement clic sur un itemrenderer n'active pas l'evenement clic sur la datagrid entiere.
Je m'explique :
Lorsque je clic sur un item de la datagrid j'affiche une fenetre de détails concernant l'objet ( proprieté itemClick de la datagrid)
Mais lorsque je clic sur mon itemrenderer ( une checkbox) je ne souhaite pas que la fenetre de détails précédemment évoqué s'affiche.
Il me faudrait donc désactivé l'évenement itemclick pour l'itemrender.
Cela est il réaslisable?
PatoshSalut Patosh,
tu peux faire un test dans ton handler itemClick pour vérifier si il s'agit d'un click sur ta checkbox et agir en conséquence ;)
Jim_Nastiq