Problème de contexte

Résolu
Venusx117 Messages postés 14 Date d'inscription mercredi 10 décembre 2003 Statut Membre Dernière intervention 19 juillet 2006 - 18 juil. 2006 à 00:37
Venusx117 Messages postés 14 Date d'inscription mercredi 10 décembre 2003 Statut Membre Dernière intervention 19 juillet 2006 - 19 juil. 2006 à 09:31
Bonjour

Je souhaite réaliser un menu dynamique en Flash. Pour cela, j'ai créé un composant MenuBTN qui est en quelque sorte un bouton standard configurable.

Ce composant dispose:
- d'une propriété picture: l'image que l'on veut afficher sur le bouton, cette propriété étant d'ailleurs visible dans l'inspecteur de composant
- d'un événément onClick: pour définir la fonction à exécuter au clic

J'ai créé un fichier xml qui contient les noeuds suivants (exemple):
<menubuttons>
<menubutton picture= "chapters/home.jpg" clip="chapters/home.swf"/>
<menubutton picture="chapters/artists.jpg" clip="chapters/artists.swf"/>
<menubutton picture="chapters/contact.jpg" clip="chapters/contact.swf"/>
</menubuttons>

Dans mon FLA, je charge mon fichier XML dans un object xmlMenuBTN

Ensuite, je souhaite créer, dans un clip vide "menu", autant de boutons que de noeuds <menubutton> , je fais donc:
for( var i = 0; i < xmlMenuBTN.firstChild.childNodes.length; i++ ) {
var tmp = this.menu.createObject( "MenuBTN", "menuBTN" + 1, this.menu.getNextHighestDepth() );
tmp._x = i * 70; // Je décale chaque bouton de 70 pixels
tmp.picture = xmlMenuBTN.firstChild.childNodes[ i ].attributes.picture;  // Je définis l'image à afficher
tmp.onClick = function() {
trace( xmlMenuBTN.firstChild.childNodes[ i ].attributes.clip ); // Pour l'instant, je me contente d'afficher l'adresse du SWF.
// A l'avenir, je le chargerai dans mon clip, principal
};
}

A l'exécution du projet, les boutons ont bien une image différente, correspondant aux attributs picture des noeuds <menubutton>. Mais au clic sur n'importe quel bouton, trace() m'affiche à chaque fois "undefined".
Je comprends vite (enfin, j'espère), que c'est parce que xmlMenuBTN.firstChild.childNodes[ i ].attributes.clip cherche la valeur de xmlMenuBTN.firstChild.childNodes[ 3 ].attributes.clip qui n'existe pas.

Je fais donc la correction suivante:
for( var i = 0; i < xmlMenuBTN.firstChild.childNodes.length; i++ ) {
var tmp = this.menu.createObject( "MenuBTN", "menuBTN" + 1, this.menu.getNextHighestDepth() );
tmp._x = i * 70; // Je décale chaque bouton de 70 pixels
tmp.picture = xmlMenuBTN.firstChild.childNodes[ i ].attributes.picture;  // Je définis l'image à afficher
  var tmpURL = new String( xmlMenuBTN.firstChild.childNodes[ i ].attributes.clip );
  tmp.onClick = function() {
    trace( tmpURL ); // Pour l'instant, je me contente d'afficher l'adresse du SWF.
                     // A l'avenir, je le chargerai dans mon clip, principal
  };
}

Mais là, chaque bouton m'affiche "chapters/contact.swf", c'est-à-dire l'attribut clip du dernier noeud <menubutton>.

Quelqu'un connaît-il une parade au problème?

11 réponses

Venusx117 Messages postés 14 Date d'inscription mercredi 10 décembre 2003 Statut Membre Dernière intervention 19 juillet 2006
19 juil. 2006 à 09:31
Bon, la diffusion d'événéments est en réalité très simple, 'suffisait d'ajouter dispatchEvent( { type: eventName, target: this } ) dans les fonctions de mon composant et voilà tout...
3
cs_Girou Messages postés 1203 Date d'inscription lundi 10 mars 2003 Statut Membre Dernière intervention 23 juillet 2009 2
18 juil. 2006 à 08:37
Salut,



c'est normal que chaque bouton affiche "chapter/contact.swf" car a chaque passage de la boucle tu redéfinis tmpURL et Flash ne garde que la nouvelle valeur en mémoire -> lorsque chaque bouton appel tmpURL il ressort toujours la même valeur puisque chaque bouton fait référrence à la même variable.



Bon, pour contourner le problème, j'ai peut-être une solution :
mettre ton objet XML en variable global, c'est à dire accessible de partout :



_global.xmlMenuBTN=.....

Mettre le _global devant chaque référence de l'objet xmlMenuBTN
Mais ca suppose que tu dois garder l'objet XML en mémoire tout le temps.



Une autre idée qui me vient est de créer une variable _clip pour chacun des menu.createObject() soit :
ajouter une ligne de code dans la  boucle :

tmp._clip=xmlMenuBTN.firstChild.childNodes[ i ].attributes.clip



et changer le onClick

tmp.onClick = function() {
    trace(this._clip)
  };


solution plus élégante, mais je suis pas sur qu'elle fonctionne avec les menus, que je n'ai jamais testé.

Bonne journée...
0
cs_goldenboy68 Messages postés 1596 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 9 juin 2011 2
18 juil. 2006 à 09:24
La 2ème solution proposée est celle à utiliser ..._global est plutôt déconseillé quand on peut l'éviter.

@+! Samy
0
Venusx117 Messages postés 14 Date d'inscription mercredi 10 décembre 2003 Statut Membre Dernière intervention 19 juillet 2006
18 juil. 2006 à 13:12
J'en suis venu à la même solution. Ajouter une variable "_clip" à tmp a été la seule alternative. Est-ce que cette solution fonctionne même si la classe MenuBTN est statique (j'entends par là que la classe n'ait pas été déclarée comme ça: dynamic class MenuBTN {...} ? Cependant, est-il possible d'attacher un écouteur au composant, du style ...

var l:Object = new Object();
l._clip = xmlMenuBTN.firstChild.childNodes[ i ].attributes.clip;
l.onRelease = function() {
trace( this._clip );
}
tmp.addListener( l );

... Ou quelque chose du genre? Je ne sais pas encore utiliser ce mécanisme et ce serait une bonne raison de m'y mettre, mais j'aurais besoin d'un connaisseur, parce que les tuto sur le Web ne me semble pas fort clairs...
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_goldenboy68 Messages postés 1596 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 9 juin 2011 2
18 juil. 2006 à 13:26
Pour faire ton menu, tu n'as pas besoin de classe, ni d'écouteur à priori. C'est un truc basique, et l'AS1 devrait très bien faire l'affaire.

Maintenant si tu veux, tu peux directement te mettre à l'AS3...très très borné, mais ce sera l'avenir.

En fait, je comprends pas bien ta question.

1. Tu boucles sur ton XML
2. Pour chaque noeud tu crées un objet (pkoi pas un createEmptyMovieClip au fait?)
3. Tu affectes à une propriété _clip, le nom d'un clip contenu dans un attribut du noeud actuel
4. Tu déclares l'évènement sur le onClick de ton objet temp, et tu fais référence à sa propriété avec this._clip

Tout est bon là. Par contre, tu ne pourras pas définir d'autre évènement onRelease sur le _clip (il y aurait interférence et seul l'un des 2 sera réalisé).

@+! Samy
0
Venusx117 Messages postés 14 Date d'inscription mercredi 10 décembre 2003 Statut Membre Dernière intervention 19 juillet 2006
18 juil. 2006 à 14:00
En fait le composant MenuBTN contient une animation qu'un bouton standard ne peut pas faire. Le MenuBTN lit une animation quand le curseur passe dessus, et lit l'animation à l'envers quand le curseur quitte la surface du bouton, à partir de l'image clé courante. C'est à dire que quand le curseur passe dessus pendant 12 images, puis sort, le bouton lit l'animation de l'image 1 à l'image 12, puis de l'image 12 à l'image 1.
C'est pour ça qu'un bouton normal ne fonctionnerait pas, et qu'un composant est plus simple à utiliser.

Par contre, au clic (onRelease), l'animation du bouton se place sur une image clé. Donc si je veux d'une part mettre à jour l'animation, et d'autre part effectuer un traitement au clic, je pense qu'il me faut un écouteur.

Comme ça, au clic, il met à jour l'animation (grâce à MenuBTN.onRelease(), qui est configuré dès l'initialisation du composant, d'où l'intérêt du composant), puis l'écouteur réalise son traitement (monEcouteur.onRelease).

Mais je ne sais pas encore mettre en place le mécanisme et j'aurai besoin de conseils.
0
cs_goldenboy68 Messages postés 1596 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 9 juin 2011 2
18 juil. 2006 à 15:06
Hmmm....c'est pas très clair!

Les boutons standards sont limités, OK, mais un MovieClip pourrait faire ce que tu veux. (un composant c'est différent...je pense pas que c'est d'un composant que tu as besoin).

Pour le onRelease, à mon avis tu dois pouvoir faire les 2 opérations dans la même gestion d'évènement.

Qu'as-tu dans le MenuBTN.onRelease() ? Et que voudrais-tu avoir dans monEcouteur.onRelease?

@+! Samy
0
Venusx117 Messages postés 14 Date d'inscription mercredi 10 décembre 2003 Statut Membre Dernière intervention 19 juillet 2006
18 juil. 2006 à 15:40
J'ai développé mon bouton en tant que composant pour apporter une simplicité d'utilisation.
Il est vrai que l'on peut tout faire sans les composants, mais le développement de composants est plus efficace, et en plus, c'est intéressant.

Dans MenuBTN.onRelease(), pour l'instant, j'ai la fonction suivante:
function() {
this.anim.gotoAndStop( 12 ); // exemple
this.onClick();
}

et pour définir un traitement, je fais:
MenuBTN.onClick = function() {
trace( "yodeleï hihou!!" ); // ... exemple
}

Cette méthode fonctionne très bien, mais, maintenant, je voudrais un truc dans le genre:
function() {
this.anim.gotoAndStop( 12 ); // exemple
/* du code comme dispatchEvent(), enfin, il me semble, 'pas sûr */
}

et un Listener qui contient une fonction onRelease.
function() {
trace( "yodeleï hihou!!" );
}

... ce qui est plus intéressant puisque grâce aux écouteurs, on peut effectuer plusieurs traitements sur un simple clic, parce qu'on peut attacher plusieurs écouteurs à un diffuseur... à ce que j'ai compris.
0
cs_goldenboy68 Messages postés 1596 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 9 juin 2011 2
18 juil. 2006 à 15:58
Oui, mais dans ton cas, tu te compliques beaucoup trop la vie!!!
Les composants, ce sont des trucs génériques que tu crées pour pouvoir les réutiliser...à mon avis, c'est un peu trop précis ce que tu fais pour en faire un composant. A la limite, j'en ferai une classe si tu veux vraiment programmé OO.

this.createEmptyMovieClip("conteneurBoutons", 1);

// tu fais ta boucle
var temp:MovieClip = this.conteneurBoutons.createEmptyMovieClip("temp", "temp"+itérateur, this.conteneurBoutons.getNextHighestDepth());
temp._clip = tonXML.attributes.clip;

temp.onRelease = function(){
    this._clip.gotoAndStop(12);
    for(i = 1; i<=nb_de_boutons;i++){
        this._parent["bouton"+i].gotoAndStop(1);
    }
}

...je sais pas exactement ce que tu veux faire, mais je pense qu'en utilisant les bons ciblages, tu devrais sans soucis t'en sortir sans utiliser d'écouteur.

@+! Samy
0
Venusx117 Messages postés 14 Date d'inscription mercredi 10 décembre 2003 Statut Membre Dernière intervention 19 juillet 2006
18 juil. 2006 à 16:27
C'est évident que des solutions alternatives sans composants sont envisageables, mais dans l'utilisation, je trouve que...
var tmp = this.createObject( "MenuBTN", "menubtn", this.getNextHighestDepth() );
tmp.picture = monXML... ...attributes.picture;
tmp._clip = monXML... ...attributes.clip;
tmp.onClick = function() {
trace( this._clip );
}

... et plus simple que...
var tmp = this.attachMovie( "MenuBTN", "menubtn", this.getNextHighestDepth() );
tmp.anim.loadMovie( monXML... ...attributes.picture );
tmp._clip = monXML... ...attributes.clip;
tmp.onRelease = function() {
tmp.gotoAndStop( 12 );
trace( this._clip );
}

...parce que dans la deuxième solution, il faut savoir comment fonctionne le bouton: faire un "gotoAndStop( 12 )" sous-entend que l'on connaît la structure du bouton. Moi, je le sais, mais le collègue qui l'utilisera ne doit pas être forcé de la savoir pour l'utiliser.
De plus, le bouton que j'ai développé charge l'image de façon asynchrome, lance une anim qui ne fait apparaître le bouton que quand cette image est chargée, et affiche un symbôle graphique standard à la place de l'image si son chargement a échoué (histoire d'avoir un affichage quand même).

Il est évident qu'utiliser de simples MovieClips est possible, mais s'il faut mettre en place toutes ces fonctionalités à chaque bouton que l'on crée, ce n'est pas productif.

Le mécanisme de diffuseur/écouteur m'intéresse parce que je ne sais pas forcément, à terme, ce que va faire le bouton. S'il n'est fait que pour rediriger l'utilisateur sur une page Web, effectivement, un MovieClip est suffisant, je mets un getURL dans une fonction et voilà tout. Mais si on veut en faire un composant plus intéressant, le mécanisme diffuseur/écouteur s'avère hyper puissant, puisqu'un clic pourra lancer n traitements, selon ce que voudra faire le développeur, qui n'est pas forcément moi.
0
cs_goldenboy68 Messages postés 1596 Date d'inscription samedi 3 janvier 2004 Statut Membre Dernière intervention 9 juin 2011 2
18 juil. 2006 à 16:47
Ok, je pensais que c'était un simple menu que tu voulais faire...si c'est pour du collaboratif, le composant est bien sûr intéressant...pour la diffusion d'évènements, je l'ai déjà utilisé, mais je pourrais pas te dire dans ton cas comment l'adapter.

@+! Samy
0
Rejoignez-nous