Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox
Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par Nataly, le 19 mai 2010

Introduction
Classe de base (#1)
Classe de base (#2)
Héritage et surcharge (#1)
Héritage et surcharge (#2)
Diffuser des événements
Classe liée
Classe de document
Classe externe : une visionneuse (#1)
Classe externe : une visionneuse (#2)
Classe externe : méthodes statiques

Classe liée

Une classe liée, c'est la même chose qu'une classe de base, si ce n'est qu'on ne peut pas lier plusieurs symboles à la même classe comme on l'a vu ici.

Quel intérêt alors ?

L'intérêt principal c'est que ça mène tout droit au composant ;-), l'intérêt second c'est qu'on peut l'initialiser à la création, en utilisant addChild.
Débarrassons nous de cette histoire d'initialisation, ensuite on jouera à transformer un symbole lié à une classe en composant… Oui, oui, vous avez bien entendu, on peut le faire (Bonus !).

Exemple avec la classe SimpleButton

Plutôt qu'illustrer ce chapitre avec un symbole clip, nous allons le faire avec un symbole bouton. D'une pierre deux coups :)

Puisque l'intérêt de la classe liée c'est de permettre l'initialisation à la création (mot clé new) considérons le cas typique suivant : on voudrait un beau bouton, avec graphisme maison qui déchire tout et un champ texte pour y écrire l'intitulé du bouton.

Ensuite on pourrait ajouter autant d'instances (occurrences) que nécessaire comme suit :

var btAcceuil:BoutonPerso=new BoutonPerso("Accueil");
var btInfo:BoutonPerso=new BoutonPerso("Qui sommes nous ?");
var btProduits:BoutonPerso=new BoutonPerso("Nos Produits");
Menu.addChild(btAccueil)
btAccueil.y=0;
Menu.addChild(btInfo);
btAccueil.y=55;
// etc…


La classe

Commençons par la classe, ensuite on fera le bouton qu'on y associera. (Si vous avez envie de jouer à faire du beau bouton tout de suite, retenez vous : vous seriez obligés de tout recommencer dès l'étape suivante).

Comme d'habitude, classe et fichier fla de test doivent être dans le même répertoire (on a vu comment s'organiser autrement ). En fait, vous savez la construire cette classe, ça obéit aux mêmes règles que ce que nous venons de voir (une chance), donc même modèle qu'une classe de base, si ce n'est que dans le cas qui nous occupe, il s'agit d'étendre non pas la classe MovieClip, mais la classe SimpleButton, et donc d'importer non pas flash.display.MovieClip, mais flash.display.SimpleButton.

L'information est dans la doc. Posez le curseur dans votre code sur SimpleButton, enfoncez la touche F1, regardez tout en haut :
Package flash.display
Classe public class SimpleButton

Allez, zou ! Un fichier .as, un package, dedans une classe, dedans un constructeur, un trace pour tester…

package {
	import flash.display.SimpleButton;
	public class BoutonPerso extends flash.display.SimpleButton {
 
		public function BoutonPerso():void {
			trace("constructeur BoutonPerso");
		}
	}
}


Le .fla

Du côté du fla, dans la bibliothèque, un bouton avec une forme et un champ texte : txtTitre (faites simple surtout, c'est très provisoire), case exporter pour ActionScript cochée, champ Classe renseigné du nom de la classe (ici BoutonPerso).


Dans le panneau action de l'image 1 de la scène :

var bouton1:BoutonPerso=new BoutonPerso ();
addChild(bouton1);
bouton1.x=bouton1.y=50;

Testez, jusque là rien de neuf. On a dit que l'intérêt de la classe liée c'est l'initialisation à la création. Allons y donc, ajoutons un paramètre au constructeur :

// la classe
public function BoutonPerso(pTitre:String):void {
	trace("constructeur BoutonPerso "+pTitre);
}
//le fla
var bouton1:BoutonPerso=new BoutonPerso ("Coucou");
addChild(bouton1);
bouton1.x=bouton1.y=50;

Plus rien pour vous surprendre, si ce n'est que ça crie quand on a le culot de poser directement une instance sur la scène :
ArgumentError: Error #1063: Non-correspondance du nombre d'arguments sur BoutonPerso(). 1 prévu(s), 0 détecté(s).
Suivi de tout un tas d'insanités…

Normal, l'instance posée sur la scène invoque le constructeur sans argument (comment ferait-elle ?) or le constructeur en prévoyait un…
Qu'à cela ne tienne, il suffit de le rendre facultatif en précisant une valeur par défaut.

public function BoutonPerso(pTitre:String="truc"):void {

Nous voilà parés.

Qui vous savez s'énerve derrière son clavier. Lui il veut écrire le titre dans le champ texte, c'est bien le but non ? Et bien pas possible, ce fichu machin prétend qu'il n'y pas de champ texte nommé txtTitre… Ça fait dix fois qu'il vérifie, bien sûr que si !

Les états de bouton

En effet :

public function BoutonPerso(pTitre:String="truc"):void {
	trace(this);
	trace(this.txtTitre);
}

… nous renvoie :

[object BoutonPerso]
null

Il est pas gonflé lui… Mais, null toi même !

En fait c'est à cause de cette particularité des boutons qui veut qu'ils présentent différents visuels selon la position/action de la souris. Dans l'ide les images sont nommées Haut, Dessus, Abaissé et Cliqué. C'est ce qu'on appellera ici les états.
On accède aux états à l'aide des propriétés upState, overState, downState et hitTestState qui renvoient un objet d'affichage utilisé comme visuel associé à l'état considéré
Concrètement, il va s'agir pour nous de regrouper le visuel de chacun des états dans un clip, ensuite nous pourrons accéder au contenu via la propriété idoine.

Pour commencer contentons nous de construire un clip pour l'état Haut (chez moi Mv_EtatHaut). Il contiendra a minima une forme et un champ texte nommé txtTitre (vous pouvez tout bonnement convertir ce que vous avez avec F8 après avoir sélectionné la forme et le champ texte).

On peut maintenant récupérer le clip via la propriété upstate qui renvoie un displayObject de type MovieClip

	public function BoutonPerso(pTitre:String="truc"):void {
		trace("upstate : "+this.upState);
	}
upstate : [object MovieClip]

Et on accède à txtTitre tout normalement (en ayant pris soin de transtyper en MovieClip) :

	public function BoutonPerso(pTitre:String="truc"):void {
		trace("upstate : "+this.upState);
		trace("txtTitre "+MovieClip(upState).txtTitre);
		MovieClip(upState).txtTitre.text=pTitre;
	}
upstate : [object MovieClip]
txtTitre [object TextField]

On pause une instance sur la scène et comme on l'espérait, à l'exécution le champ texte affiche “truc”, la valeur par défaut.

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Les deux autres états (survol et abaissé) affichent “pour voir”, normal c'est ce qu'on avait mis dans le champ texte du symbole, justement pour y voir quelque chose.
Ce qui peut décontenancer, c'est de constater que même si seule l'image Haut contient un visuel (comme sur la copie d'écran) les deux autres états affichent tout de même quelque chose. C'est comme ça, c'est à savoir : si seul l'état Haut (upState) a été crée dans symbole, le lecteur le duplique pour les deux autres états. De la même manière si l'état Abaissé (downState) n'a pas été crée, c'est l'état Dessus (overState) qui est dupliqué.

Finitions :
Libre à vous maintenant de créer les autres clips pour faire les visuels des états survol et abaissé. Il faudra bien sûr avoir recours aux propriétés overState et downState pour initialiser le champ de texte.
Par ailleurs, puisque on a prévu l'éventualité où les boutons seraient posés directement sur la scène il faut faire en sorte qu'ils puissent afficher autre chose que truc (la valeur par défaut). Il nous faut une propriété titre, donc un couple d'accesseurs comme vous savez les faire maintenant ;)

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

// mise en œuvre fla
 
// bt1 sur la scène
bt1.titre="Accueil";
 
// une instance ajoutée dynamiquement
var bouton1:BoutonPerso=new BoutonPerso ("Infos");
addChild(bouton1);
package {
	import flash.display.SimpleButton;
	import flash.display.MovieClip;
 
	public class BoutonPerso extends flash.display.SimpleButton {
		private var _titre:String;
		public function BoutonPerso(pTitre:String=""):void {
			_titre=pTitre;
			MovieClip(upState).txtTitre.text=_titre;
			MovieClip(downState).txtTitre.text=_titre;
			MovieClip(overState).txtTitre.text=_titre;
		}
		public function set titre(pTitre:String):void {
			_titre=pTitre;
			MovieClip(upState).txtTitre.text=_titre;
			MovieClip(downState).txtTitre.text=_titre;
			MovieClip(overState).txtTitre.text=_titre;
		}
		public function get titre():String {
			return _titre;
		}
	}
}

Pour résumer

Et ben voilà :) C'est pas plus, on a vu que la classe liée se construit exactement selon les mêmes principes que la classe de base, donc rien de plus à mémoriser (chic !)

Quant à la classe SimpleButton, l'important à en connaitre c'est l'histoire des états qui se doivent d'être une instance de clip.

N'allez pas vous emmêler : On est bien d'accord qu'une classe qui étend SimpleButton peut être indifféremment une classe de base ou une classe liée, je ne l'ai utilisée dans ce contexte que dans l'idée de nous gagner un peu de temps (et d'avoir quelque chose à illustrer :mrgreen:)

Vers les composants perso

Du coup on s'offre un détour par le composant.
Pour construire un composant il faut impérativement que la classe associée au symbole destiné à devenir composant le soit via le champ Classe, une classe liée donc.

Même si ça a à voire avec ce tuto, du point de vue de la classe liée, vous pouvez sauter la partie composant et continuer par le chapitre suivant : classe de document. Le module composant n'est qu'un détour où rien de nouveau sur les classes ne sera vu.

Itinéraire direct —> Classe de document
Itinéraire découverte —> lien composant (à écrire)