Article publié par Nicolas Jozwiak le 19 juin 2008.
Catégorie(s) : Java / JEE, RIA
Après avoir étudié dans un précédent billet la mise en place d’une galerie d’image, nous allons voir le drag and drop. Tous les composants Flex supportent le drag and drop, mais certains composants dont le Tree, la List et le DataGrid possèdent quelques options supplémentaires.
A travers ce billet, nous allons mettre en place le drag and drop pour le composant List.
Jeu de données
<mx:Array id="sports">
<mx:Object label="Football"/>
<mx:Object label="Basketball"/>
<mx:Object label="Handball"/>
<mx:Object label="Tennis"/>
<mx:Object label="Karate"/>
<mx:Object label="Judo"/>
<mx:Object label="Boxe"/>
<mx:Object label="Marathon"/>
</mx:Array>
Nous créons une liste (avec un id='sports') composée d’objets qui ont comme attribut label.
Simple drag
DragAndDrop.mxml
<mx:Panel title="Select some sports" layout="horizontal" width="100%" height="204">
<mx:VBox width="50%">
<mx:Label text="Available sports"/>
<mx:List id="provider" dataProvider="{sports}" width="100%"
height="138"
allowMultipleSelection="true"
dragEnabled="true"
/>
</mx:VBox>
<mx:VBox width="50%">
<mx:Label text="My sports"/>
<mx:List id="selected" width="100%" height="138"
dropEnabled="true"
/>
</mx:VBox>
</mx:Panel>
Cet écran est composé du composant Panel dans lequel se trouvent deux composants (layout) VBox. Ce dernier permet d’organiser les composants verticalement.
Etudions les attributs du composant List:
id: id du composantdataProvider: la liste précédemment définie et identifiée par son id (iesports)allowMultipleSelection: permet de sélectionner plusieurs lignesdragEnabled: les éléments de la liste peuvent être « dragé »dropEnabled: la liste peut recevoir de nouveaux éléments
Le résultat:
Nous voyons donc que la première liste (id='provider') permet de sélectionner les éléments et de les placer dans la deuxième liste (id='selected'). Cependant, vous remarquerez que l’élément placé dans la deuxième liste est toujours présent dans la liste d’origine. Améliorons ce drag and drop.
Drag and drop
DragAndDropMoveEnabled.mxml
<mx:Panel title="Select some sports" layout="horizontal" width="100%" height="204">
<mx:VBox width="50%">
<mx:Label text="Available sports"/>
<mx:List id="provider" dataProvider="{sports}" width="100%" height="138"
allowMultipleSelection="true"
dragEnabled="true"
dragMoveEnabled="true"
/>
</mx:VBox>
<mx:VBox width="50%">
<mx:Label text="My sports"/>
<mx:List id="selected" width="100%" height="138"
dropEnabled="true"
/>
</mx:VBox>
</mx:Panel>
L’attribut dragMoveEnabled a été ajouté à la première liste et permet de déplacer les éléments dans la deuxième liste.
Le résultat:
Drag and drop des deux listes
Nous allons encore améliorer notre exemple en faisant en sorte que les éléments puissent être déplacés dans les deux listes:
<mx:Panel title="Select some sports" layout="horizontal" width="100%" height="204">
<mx:VBox width="50%">
<mx:Label text="Available sports"/>
<mx:List id="provider" dataProvider="{sports}" width="100%" height="138"
allowMultipleSelection="true"
dragEnabled="true"
dropEnabled="true"
dragMoveEnabled="true"
/>
</mx:VBox>
<mx:VBox width="50%">
<mx:Label text="My sports"/>
<mx:List id="selected" width="100%" height="138"
dropEnabled="true"
dragEnabled="true"
dragMoveEnabled="true"
/>
</mx:VBox>
</mx:Panel>
Les attributs précédemment décrits (dragEnabled, dragMoveEnabled, dropEnabled) ont été ajoutés à chacune des listes. Dorénavant, il est possible de déplacer les éléments dans la deuxième liste, et de les replacer dans la première liste.
Le résultat:
Drag and drop d’images
Nous allons maintenant voir le drag and drop avec des images. Pour l’exemple, nous allons prendre le jeu de données suivant:
[Embed(source='images/paysage1.jpg')] public var paysage1:Class; [Embed(source='images/paysage2.jpg')] public var paysage2:Class; [Embed(source='images/paysage3.jpg')] public var paysage3:Class; [Embed(source='images/paysage4.jpg')] public var paysage4:Class;
DragAndDropImages.mxml
<!-- The Canvas is the target -->
<mx:Canvas id="cvs"
width="500" height="500"
borderStyle="solid"
backgroundColor="#DDDDDD"
dragEnter="dragEnterHandler(event);"
dragDrop="dragDropHandler(event);">
<mx:Image id="pays1" source="{paysage1}" x="10" mouseMove="mouseOverHandler(event);"/>
<mx:Image id="pays2" source="{paysage2}" x="165" mouseMove="mouseOverHandler(event);"/>
<mx:Image id="pays3" source="{paysage3}" x="250" y="250" mouseMove="mouseOverHandler(event);"/>
<mx:Image id="pays4" source="{paysage4}" x="140" y="140" mouseMove="mouseOverHandler(event);"/>
</mx:Canvas>
ActionScript
// initiates the drag-and-drop operation.
private function mouseOverHandler(event:MouseEvent):void
{
var dragInitiator:Image = event.currentTarget as Image;
var ds:DragSource = new DragSource();
ds.addData(dragInitiator, "img");
var imageProxy:Image = new Image();
imageProxy.source = event.currentTarget.source;
imageProxy.height=15;
imageProxy.width=15;
DragManager.doDrag(dragInitiator, ds, event, imageProxy);
}
// enables dropping.
private function dragEnterHandler(event:DragEvent):void {
if (event.dragSource.hasFormat("img"))
{
DragManager.acceptDragDrop(Canvas(event.currentTarget));
}
}
// The dragDrop event handler for the Canvas container
// sets the Image control's position by
// "dropping" it in its new location.
private function dragDropHandler(event:DragEvent):void {
Image(event.dragInitiator).x = Canvas(event.currentTarget).mouseX;
Image(event.dragInitiator).y =
Canvas(event.currentTarget).mouseY;
}
Dans cet exemple, chacun des composants Image ont les attributs suivants :
id: id de l’image.source: la source de l’image.x, y: coordonnées pour l’initialisation du placement de l’image.mouseMove: appelle la fonction mouseOverHandler(event).
Cette dernière fonction se décompose de la manière suivante :
- on indique sur quel composant le drag and drop va avoir lieu:
var dragInitiator:Image = event.currentTarget as Image;
- les données à déplacer, içi l’image:
var ds:DragSource = new DragSource(); ds.addData(dragInitiator, "img");
- definition d’un drag proxy (optionnel). Dans notre exemple nous avons pris l’image comme drag proxy:
var imageProxy:Image = new Image(); imageProxy.source = event.currentTarget.source;
- initialisation du drag and drop:
DragManager.doDrag(dragInitiator, ds, event, imageProxy);
Ensuite, il y a un composant Canvas dans lequel il est possible de glisser/déposer les images. Afin que ce composant accepte le drag and drop, deux attributs ont été ajoutés :
dragEnterappelle la méthodedragEnterHandler:
private function dragEnterHandler(event:DragEvent):void {
if (event.dragSource.hasFormat("img"))
{
DragManager.acceptDragDrop(Canvas(event.currentTarget));
}
}
Si le drag and drop est effectué sur une image, alors le composant Canvas accepte l’opération.
dragDropappelle la méthodedragDropHandler:
private function dragDropHandler(event:DragEvent):void {
Image(event.dragInitiator).x = Canvas(event.currentTarget).mouseX - 70;
Image(event.dragInitiator).y = Canvas(event.currentTarget).mouseY - 50;
}
Lorsque l’image est déplacée (drop), on calcule ses nouvelles coordonnées.
Le résultat:
Vous pouvez télécharger les sources sur le SVN de Xebia France.


Complet
Twitter







Sympa ce post qui montre le support direct de Drag & Drop pour les composants DnD-enabled comme les List, DataGrid, Tree. Et qui montre ensuite comment faire intervenir le DragManager quand il s’agit d’une Image.
Dans l’exemple de l’image ci-dessus, au moment du Drop, l’image ne reste pas à l’endoit naturel. Voici un billet qui propose un complément sur ce point : http://flex.scoutant.org/index.php?post/2008/10/No-Move-API-for-Flex-Falling-back-Drag-Drop-API
[...] les précédents articles sur Flex, nous avons vu la mise en place d’une galerie d’images ainsi que le drag and drop. Ce billet sera consacré à la création de composants Flex génériques et réutilisables. Nous [...]
[...] est adapté pour réaliser des interactions utilisateurs trés riches, trés visuelles : slider, drag&drop, transitions visuelles et autres effets visuels… . A l’inverse, HTML reste la [...]