Drag'n'Drop entre 2 composants

  • warning: array_map(): Argument #2 should be an array in /var/www/titouille.ch/www/modules/system/system.module on line 1050.
  • warning: array_keys() expects parameter 1 to be array, null given in /var/www/titouille.ch/www/includes/theme.inc on line 1845.
  • warning: Invalid argument supplied for foreach() in /var/www/titouille.ch/www/includes/theme.inc on line 1845.
Portrait de titouille

Question posée sur le forum de Développez.com, ça m'a titillé un peu l'esprit et j'ai voulu m'y essayer.

Comment faire un drag'n'drop entre 2 dataGrid. Au départ, j'ai fouillé un peu dans les gestionnaires d'évenements de la grille sans pour autant trouver des évenements adaptés à ce genre de cas...
Il existe les évenements standard : change, cellPress
Il existe également des évenements "masqués", qui correpondent à des évenements de contenu interne à la grille. Par exemple, on peut décomposer une grille en lignes. Chaque ligne est récupérable via myDg.content_mc.listRow1x
ou x est l'index de la ligne à récupérer.

A partir de là, nous pouvons récupérer le clip de "fond" de la ligne, qui se nomme bG_mc. Ce dernier à une multitude d'évenements : press, release, rollOver, rollOut, dragOver, dragOut...

Malheureusement, il n'a pas l'évenement essentiel pour du drag'n'drop... onReleaseOutside...

Pour finir, après quelques disscussions sur le forum POO de Flash-France, on m'a réorienté vers l'évenement mouseUp, et au final, ça fonctionne plutôt bien Smile

Voici un exemple non exhaustif, qui permet de passer un élément de la première grille à la seconde. Pour la manipulation inverse, il n'y a qu'a revoir le code pour l'inverser.

Tout d'abord, un fla avec 2 grilles, nommées respectivement dg1 et dg2.
Ensuite, en librairie, un clip (exporté pour AS) qui représente un rectangle de 200/20 px, centré. A l'intérieur de ce dernier, un autre clip de 18/18, centré également, qu'on va nommer "sensibility" et qui va servir à tester si il est en collision avec la seconde grille lors du relachement.

Puis enfin, le code suivant :

// utilisation du Delegate pour simplifier
import mx.utils.Delegate;
 
//
// déclaration des variables de base
var dragFlag:Boolean = false;
var index:Number = -1;
 
//
// remplissage de la première grille
dg1.dataProvider = [
		{ data:1, label:"label 1" },
		{ data:2, label:"label 2" },
		{ data:3, label:"label 3" },
		{ data:4, label:"label 4" },
		{ data:5, label:"label 5" }
		];
 
//
// ajout du gestionnaire d'évenement "cellPress"
dg1.addEventListener( 'cellPress', Delegate.create( this, cellPressHandler ) );
 
//
// création du gestionnaire "cellPress"
function cellPressHandler( evt:Object ):Void
	{
	dragFlag = true;
	index = dg1.selectedIndex;
 
	//
	// on ajoute notre clip rectangulaire qu'on attache à la souris
	//
	var dragItem:MovieClip = attachMovie( 'dragItem', 'dragItem', 10, { _x:_xmouse, _y:_ymouse } );
	dragItem.createTextField( 't', 1, -100, -10, 30, 20 );
 
	var t:TextField = dragItem['t'];
	t.text = "index " + index.toString();
	startDrag( dragItem, true, 0, 0, 400, 550 );
	}
 
//
// création de l'objet gestionnaire pour le mouseUp
var obj:Object = new Object( { owner:this } );
obj.onMouseUp = function()
	{
	// on fait quelque chose seulement si "dragFlag" est à "true"
	if( this.owner.dragFlag )
		{
		this.owner.onStopDrag();
		this.owner.dragFlag = false;
		}
	}
 
//
// ajout du gestionnaire à la souris
Mouse.addListener( obj );
 
//
// création de la méthode d'arrêt du drag'n'drop
function onStopDrag():Void
	{
	// on teste si le clip "sensibility" à l'intérieur de notre item volant
	// est dans la zone de la seconde grille
	if( dragItem.sensibility.hitTest( dg2 ) )
		{
		// si oui, on supprime l'élément de la première grille
 
		// pour le mettre dans le second
		dg2.addItem( dg1.removeItemAt( index ) );
		}
	// enfin, on réinitialise notre scène
	dragItem.removeMovieClip();
	index = -1;
	}

Voilà, en espérant que ça vous donne des idées Wink




BRAVO !

Bonjour et bravo !
j'avais fini par abandonner mes recherches sur le datagrid drag'n'drop, les (trop rares) exemples trouvés sur le net étant bien trop compliquée pour le petit bidouilleur que je suis... et un jour, par hasard je tombe sur cette page : ô miracle, ça tiens en peu de lignes, ça fait pas intervenir de classes_et tout le toutim_ et ça fonctionne à merveille ! Merci !!.
Sinon, je cherche un moyen de faire permuter les lignes d'une même datagrid par le biais d'un dragndrop, et j'ai l'impression que ta méthode permettrai d'y arriver ! Si tu as une idée là dessus je serais intéressé, car j'ai eu beau faire des essais cela n'a pas été très concluant(le dragndrop, s'effectue, mais pas toujours et ne permute pas les bonnes informations) je te joins quand-même le code modifié :

]
// utilisation du Delegate pour simplifier
import mx.utils.Delegate;
 
//
// déclaration des variables de base
var dragFlag:Boolean = false;
 
var aRemplacer:Number =-1;//index de la ligne à remplacer
var sourceRemplacer:Number =-1;//index de la ligne source
//
// remplissage de la première grille
dg1.dataProvider = [
{ data:1, label:"label 1" },
{ data:2, label:"label 2" },
{ data:3, label:"label 3" },
{ data:4, label:"label 4" },
{ data:5, label:"label 5" }
];
 
 
// ajout du gestionnaire d'évenement "cellPress" et "itemRollOver"
dg1.addEventListener( 'cellPress', Delegate.create( this, cellPressHandler ) );
 
dg1.addEventListener("itemRollOver",Delegate.create( this, ecouteRollover)  );
 
function ecouteRollover( evt_obj:Object ):Void {
	//var infoContenu = event.target.getItemAt(event.target.selectedIndex).data
	aRemplacer=evt_obj.index;
 
}
// création du gestionnaire "cellPress"
function cellPressHandler( evt:Object ):Void{
	dragFlag = true;
	sourceRemplacer= dg1.selectedIndex;
 
	// on ajoute notre clip rectangulaire qu'on attache à la souris
 
	var dragItem:MovieClip = attachMovie( 'dragItem', 'dragItem', 10, { _x:_xmouse, _y:_ymouse } );
	dragItem.createTextField( 't', 1, -100, -10, 50, 20 );
 
	var t:TextField = dragItem['t'];
	t.text = dg1.getItemAt(sourceRemplacer).label;
	trace(dg1.getItemAt(sourceRemplacer).label)
	startDrag(dragItem, true, dg1._x, dg1._y, dg1._x, dg1._y+dg1.height);
}
 
 
// création de l'objet gestionnaire pour le mouseUp
var obj:Object = new Object( { owner:this } );
obj.onMouseUp = function(){
	// on fait quelque chose seulement si "dragFlag" est à "true"
	if( this.owner.dragFlag ){
 
		this.owner.onStopDrag();
		this.owner.dragFlag = false;
	}
}
 
 
// ajout du gestionnaire à la souris
Mouse.addListener( obj );
 
// création de la méthode d'arrêt du drag'n'drop
function onStopDrag():Void{
	// on teste si le clip "sensibility" à l'intérieur de notre item volant
	// est dans la zone de la seconde grille
	//if( dragItem.sensibility.hitTest( dg1 ) ){
	// si oui, on supprime l'élément de la première grille
	// pour le mettre dans le second
 
 
	if (sourceRemplacer < aRemplacer) {
		dg1.addItemAt(sourceRemplacer,dg1.removeItemAt(aRemplacer));
		dg1.selectedIndex=aRemplacer;
 
		trace("source:"+sourceRemplacer+" dest:"+aRemplacer);
		}
	if (sourceRemplacer > aRemplacer) {
		dg1.addItemAt(sourceRemplacer,dg1.removeItemAt(aRemplacer));
		dg1.selectedIndex=aRemplacer;
		trace("source:"+sourceRemplacer+" dest:"+aRemplacer);
		}		
	if (sourceRemplacer == aRemplacer) {
 
		trace("---identiques---");
		}		
 
	//}
// enfin, on réinitialise notre scène
dragItem.removeMovieClip();
 
}

Voilà, bonne journée (ou soirée, c'est selon!)

Excellente source, Mais...

bonjour,
tout d'abord ton script est fort utile et d'une qualité rare.
Cependant, un problème plutot important me pollue mon script:

principe de mon site(www.aerolyte.fr/transfert): utilisation du drag and drop en hitTest sur des dropzones, afin d'initier soit le download, soit la suppression du fichier sélectionner.

La drag ne pose aucun problème, excépté qu'il drag aussi les lignes vides de la datagrid.
je ne sais pas trop comment faire, pour résoudre ce problème.

voici mon script:

import flash.net.FileReference;
import mx.controls.gridclasses.DataGridColumn;
import mx.styles.CSSStyleDeclaration;
// Patch for header for DataGrid
#include "dgHeaderPatch.as"
import mx.utils.Delegate;
////////////////////////////////////////////////////////////////////
var dragFlag:Boolean = false;
var index:Number = -1;
// Style for DataGrid
var styleObj:CSSStyleDeclaration = new mx.styles.CSSStyleDeclaration();
styleObj.styleName = "myStyle";
styleObj.fontFamily = "Microsoft Sans Serif";
styleObj.fontSize = 12;
styleObj.fontWeight = "regular";
styleObj.color = 0x999999;

_global.styles["myStyle"] = styleObj;
public_grd.setStyle("styleName","myStyle");
public_grd.setStyle("themeColor",0xFFFFFF);
my_pb.setStyle("themeColor",0xFF9900);
// enlève le Header
public_grd.setShowHeaders(false);
public_grd.setVScrollPolicy("auto");
public_grd.setStyle("borderStyle","none");
public_grd.setStyle("vGridLines",false);
public_grd.columnNames = ["extension", "nom"];

// Icon must be symbol with a linkage identifier(string)
contactIconFunction = function (itemObj:Object, columnName:String) {
if (itemObj == undefined || columnName == undefined) {
return;
}
switch (columnName) {
case "extension" :
var extension = itemObj.extension;
return (extension == undefined ? undefined : extension);
break;
}
};

//customize columns
var col:mx.controls.gridclasses.DataGridColumn;
col = public_grd.getColumnAt(0);
col.width = 60;
col.cellRenderer = "IconCellRenderer";
col["iconFunction"] = contactIconFunction;
col = public_grd.getColumnAt(1);
col.width = 140;

//ajout du gestionnaire d'événement "CellPress"
public_grd.addEventListener('cellPress',Delegate.create(this, cellPressHandler1));
//création de l'objet gestionnaire pour le mouseUp
var obj:Object = new Object({owner:this});
obj.onMouseUp = function() {
//on fait quelque chose seulemnt si dragFlag est à "true"
if (this.owner.dragFlag) {
this.owner.onStopDrag();
this.owner.dragFlag = false;
}
};
//ajout du gestionnaire à la souris
Mouse.addListener(obj);
//
//
var fr:FileReference = new FileReference();
var dl:FileReference = new FileReference();
var ecouteur:Object = new Object();
fr.addListener(ecouteur);
ecouteur.onSelect = function(file:FileReference):Void {
file.upload("http://www.aerolyte.fr/transfert/upload.php");
};
//L'évènement onProgress est déclenchée lors de l'upload de fichier et renvoie 3 paramêtres dont 2 qui récupèrent l'état du téléchargement en cours
ecouteur.onProgress = function(file:FileReference, BytesLoaded:Number, BytesTotal:Number) {
//la méthode setProgress affecte des valeurs à la progressbar à chaque fois que l'upload se met à jour
my_pb.setProgress(BytesLoaded,BytesTotal);
};
ecouteur.onComplete = function():Void {
contact_con.trigger();
};
up_bt.addEventListener("click",this.clickEvent);
dn_bt.addEventListener("click",this.downClickEvent);

///////////////////////////////////////////////////////////////////////
// XML connecteur
contact_con.trigger();
//
//
function clickEvent() {
if (fr.browse([{description:"Image files (.jpeg, .jpg, .gif, .png)", extension:"*.jpeg;*.jpg;*.gif;*.png", macType:"JPEG;jp2_;GIFF"}, {description:"Flash Movies", extension:"*.swf", macType:"SWFL"}])) {
trace("Bien créé la dialog");
} else {
trace("Erreur de création de dialog");
}
}
function downClickEvent() {
dl.download("http://www.aerolyte.fr/transfert/dpub/"+public_grd.selectedItem.nom + public_grd.selectedItem.extension)
}
//création du gestionnaire "cellPress"
function cellPressHandler1(evt:Object):Void {
dragFlag = true;
index = public_grd.selectedIndex;
//on ajoute notre clip rectangulaire que l'on attache à la souris
var dragItem:MovieClip = attachMovie('dragItem', 'dragItem', 10, {_x:_xmouse, _y:_ymouse});
dragItem.createTextField('t',1,8,-6,140,20);
var t:TextField = dragItem['t'];
t.text = public_grd.selectedItem.nom;
t.textColor = 0x999999;
t.embedFonts = true;
t.antiAliasType = "advanced";
//
var style_fmt:TextFormat = new TextFormat();
style_fmt.font = "Police1";
style_fmt.size = 11;
t.setTextFormat(style_fmt);
startDrag(dragItem, true, 0, 0, 1000, 700);
}
// création de la méthode d'arret de drag'n drop
function onStopDrag():Void {
//on teste si le clip 'sensibility" à l'intérieur de notre item volant est dans la zone de la seconde grille
if (dragItem.sensibility.hitTest(Zonedown)) {
// si oui on supprime l'élément de la première grille, pour le mettre dans la seconde
dg2.addItem(dg1.removeItemAt(index));
}
//enfin, on réinitialise notre scène
dragItem.removeMovieClip();
index = -1;
}

Salut, j'ai un petit

Salut,

j'ai un petit problème avec l'autosize...
par exemple, dans ton code, rajoutant :
"t.autosize = true;" rien ne se passe ....

sais-tu pourquoi ?

//
// on ajoute notre clip rectangulaire qu’on attache à la souris
//
var dragItem:MovieClip = attachMovie( ‘dragItem’, ‘dragItem’, 10, { _x:_xmouse, _y:_ymouse } );
dragItem.createTextField( "t", 1, -100, -10, 30, 20 );
var t:TextField = dragItem["t"];
t.text = "index" + index.toString();
t.autosize = true;
startDrag( dragItem, true, 0, 0, 400, 550 );
}

Merci d'avance

Portrait de titouille

Déjà, c'est autoSize, pas autosize. ça devrai aider. Ensuite, passe l'autoSize à true AVANT de mettre le texte à l'intérieur du textField.

Mais en fait, tu cherche à faire quoi ?? car si c'est de l'affichage multilignes, tu dois utiliser multiline = true et wordWrap = true également, avec ton autoSize.

A++

en effet, c'est autoSize
je cherchais a faire un affichage sur une ligne avec un fond jaune.
il fallait donc appliquer un autoSize = "left" et wordwrap = false

Merci