Créer un composant dans flash MX2004

Cet article vous explique comment créer un composant dans Flash MX2004 en vous proposant un exemple concret. Je remercie Jérôme et Rmotte pour leur aide précieuse et leurs corrections apportées à ce tuto. ?

- Titre : Créer un composant dans flash MX2004

- Parution : 10 juin 2004

- Licence : Copyright ® 2004 Developpez. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. Qu'est-ce qu'un composant

- I-B. Quel type de composant nous proposons vous ?

- I-C. Propriétés de notre composant

- I-D. À quoi ressemble-t-il ?

- II. POO en MX2004

- II-A. Qu'est-ce que le classpath

- II-B. Classe dynamique ou statique

- II-C. private et public

- II-D. L'héritage

- II-E. interface et implements

- III. Étapes de création de notre composant

- IV. Code de la classe à associer au composant

- V. Structure du fichier XML

- VI. Particularité du paramètre fonction du composant

- VII. Intégrer ce composant dans une animation Flash

- VIII. Téléchargement

- IX. Conclusion

I - Introduction

Le but de ce tutoriel est de vous montrer comment créer un composant dans Flash MX 2004. Pour l'appréhender correctement, il est préférable d'avoir déjà de bonnes connaissances en Flash. Surtout en ce qui concerne les clips et les classes en général.

I-A - Qu'est-ce qu'un composant

Un composant est un objet intégrant toute une série de fonctionnalités utilisables dans n'importe quelle animation sans devoir déployer un effort particulier au niveau développement. Les composants sont disponibles dans la fenêtre des composants de Flash MX2004. Contrairement aux composants de Flash MX, ceux de MX 2004 sont compilés, il n'est donc plus possible d'éditer les composants standards tels que Checkbox, button, Scrollpane… L'avantage des composants est principalement leur réutilisabilité et leur paramétrage via la fenêtre des propriétés ou via l'inspecteur des composants. Un autre avantage est aussi que l'on peut distribuer un composant facilement. Si vous êtes indépendant, vous pourriez créer vos propres composants et les distribuer à vos clients. L'avantage est que le code associé au composant est compilé. De ce fait, la discrétion concernant la réalisation et le code source est préservée.

I-B - Quel type de composant nous proposons vous ?

Nous vous proposons une bannière d'images. Cette bannière chargera dans un scrollpane les images dont les chemins sont définis dans un fichier XML de votre choix. La structure de ce fichier XML est très simple et sera décrite plus loin. L'utilisation du composant est ultra simple.

I-C - Propriétés de notre composant

Description des propriétés

Nom de la propriété

Valeur(s) possible(s)

Description

Alpha

true ou false

Défini à true, un effet de transparence apparaîtra au survol des images. À false, aucun effet ne sera défini

Fichier Son

URL pointant sur l'emplacement du fichier son

L'URL indiquera au composant quel fichier son il faut exécuter lors du clic sur une image. Si ce paramètre est vide, aucun son ne sera joué

Fichier XML

URL pointant sur l'emplacement du fichier XML

L'URL indiquera au composant quel fichier XML contient les chemins des images

Fonction associée

Un nom de fonction que vous avez développé

La valeur que vous attribuerez éventuellement à ce paramètre doit correspondre au nom d'une fonction que vous avez développée. Cette fonction sera alors déclenchée lorsque l'utilisateur cliquera sur une image. Si vous laissez ce paramètre vide, aucune action ne sera déclenchée lors du clic sur une image. Le composant passe le clip courant en paramètre à votre fonction. Vous comprendrez vite le fonctionnement en visionnant le fichier Banner.fla disponible en téléchargement

Largeur Images

un nombre

Il sert à déterminer la coordonnée X des images. Si par exemple vous attribuez la valeur 100 à ce paramètre, les images seront positionnées tous les 100 pixels. Si vous avez des images de taille différente, il est préférable d'attribuer la plus grande taille à ce paramètre. Comme vous l'aurez sans doute deviné, il est préférable d'avoir des images de même taille pour un affichage parfait.

I-D - À quoi ressemble-t-il ?

Pour visualiser le composant, il vous faut le player 7. Allumez vos enceintes, cliquez sur « Go » et ensuite cliquez sur les images

Animation en format "flash" non supportée.
Contenu uniquement consultable en ligne à cette adresse :
https://stephaneey.developpez.com/scroller.swf

Note : pour ne pas surcharger le serveur, je n'ai uploadé que trois images.

II - POO en MX2004

Avec Flash MX 2004, Macromedia a introduit l'actionscript 2 (AS2) et a radicalement changé la philosophie de développement dans Flash. L'AS2 propose à présent des concepts proches de ceux que l'on peut trouver dans Java et C++. De cette manière, ils « standardisent » la programmation objet en Flash et permettent aux développeurs Java et C++ de s'intéresser d'avantage à Flash et de l'appréhender plus rapidement.

II-A - Qu'est-ce que le classpath

Tout d'abord vous devez savoir que toute programmation de classe doit être faite dans un fichier externe à Flash. Les classes doivent être programmées dans les fichiers .as (Flash->nouveau document->fichier actionscript). Ces fichiers .as sont stockés quelque part sur le disque dur. Afin de ne pas restreindre le choix d'emplacement de ces fichiers, Flash utilise des classpath qui pointent vers ces emplacements.

Pour définir votre propre classpath, vous pouvez aller dans le menu Edition -> préférences -> onglet actionscript -> paramètres actionscript 2. Si vous ajoutez un classpath de type « c:\monclasspath\ », vous pourrez dorénavant stocker vos fichiers .as dans le répertoire c:\monclasspath\. Vous pouvez ajouter plusieurs classpaths.

II-B - Classe dynamique ou statique

Sans le mot clé « dynamic » précédent le mot clé « class », une classe actionscript 2 est considérée comme statique. Lorsqu'une classe est statique, on ne peut pas lui ajouter des propriétés ou méthodes de manière dynamique.

Lorsqu'une classe est dynamique, on peut lui ajouter autant de propriétés et de méthodes que l'on souhaite via l'occurrence de classe que l'on a instanciée.
Exemple :

//On crée juste une classe vide pour l'exemple
class dvp{
function dvp(){

}
}
//Dans un fla
var dvpobj:dvp=new dvp();
dvpobj.MaPropriete=1; //Génère une erreur

En ajoutant le mot clé « dynamic » devant le mot clé « class », on sera autorisé à ajouter la propriété « MaPropriete ». Il en va de même pour les méthodes.
Notez cependant que cette protection ne paraît valable que lorsque l'on utilise le « strong typing », c'est-à-dire une déclaration de variable ressemblant à ceci :

var dvpobj:dvp;

Si nous avions déclaré la variable comme suit :

var dvpobj=new dvp();

Nous n'aurions pas eu de problèmes pour rajouter une propriété ou une méthode. Ceci est à mon sens un bug et ceci est malheureusement valable pour les méthodes et propriétés privées. Espérons que Macromédia réagisse rapidement à ce problème.

Le mot clé « static » s'applique aux propriétés et méthodes d'une classe. Lorsqu'on les préfixe de ce mot clé, elles sont uniquement accessibles au sein même de la classe ou par une classe ayant hérité de celle-ci. Ces méthodes et propriétés ne sont pas accessibles via l'occurrence de la classe.

Exemple :

class dvp{
function dvp(){
}
static function dvp_message(){
trace("cette méthode est statique");
}
}
//Dans un FLA
var dvpobj:dvp=new dvp();
dvpobj.dvp_message(); //Génère une erreur. Par contre, ceci est correct
dvp.dvp_message();

II-C - private et public

Une méthode ou propriété privée est une méthode qui ne peut être accédée par une occurrence de classe.

Exemple :

class dvp{
function dvp(){
}
private function affiche_message():Void{
trace("message");
}
//Dans un fla
var dvpobj:dvp=new dvp();
dvpobj.affiche_message(); //Génère une erreur

En retirant le mot clé « private » devant la déclaration de la méthode ou en le remplaçant par « public », on aurait pu accéder à cette méthode via l'occurrence dvpobj. Comme je l'ai dit ci-dessus, ce n'est valable que lorsque l'on utilise le « strong typing ».

II-D - L'héritage

L'héritage s'effectue via le mot clé « extends ». Lorsqu'une classe hérite d'une autre classe, elle peut accéder à toutes les propriétés et méthodes de cette classe, même celles déclarées en « private ».
La syntaxe est simple :

class dvp1{
function dvp1(){

}
private function affiche_message() :Void{
trace("message");
}
}
//Dans un autre fichier de classe, on définit cette classe:
class dvp2 extends dvp1{
function dvp2(){
affiche_message();
}
}

Étant donné que dvp2 a hérité des propriétés et méthodes de dvp1, on peut directement appeler une méthode de dvp1.
Note : lorsque l'on fait référence à une méthode ou une propriété, on peut préfixer cette référence via le mot clé « this ».

II-E - interface et implements

Une interface représente une définition de méthodes. Cette définition devra être respectée par les classes implémentant cette interface. L'interface ne peut contenir :

- de déclaration de propriété ;

- d'implémentation de méthode ;

- l'usage de méthodes « private » ou « static ».

L'interface comprend en somme le prototype des méthodes qui devront être utilisées par les classes qui implémentent cette interface.
Exemple :

//définition d'une interface
interface dvp_interface {
function dvp2():Number;
function dvp3():String;
}

//définition d'une classe implémentant cette interface
class dvp implements dvp_interface{
function dvp2():Number{
return 10;
}
function dvp3():String{
return "dvp";
}
}
//Cette classe est correcte, car elle respecte bien l'interface dvp_interface.
class dvp implements dvp_interface{
function dvp2():String{
return "dvp";
}
function dvp3():String{
return "dvp";
}
}
//dvp_interface. En effet la méthode dvp2 retourne un type String alors qu'elle est censée retourner un Number.

Note : toutes les méthodes définies dans l'interface doivent être implémentées dans une classe qui implémente l'interface. En cas d'omission d'une déclaration de méthode, le compilateur génèrera une erreur.
L'intérêt des interfaces est de pouvoir consolider et valider son code. Si l'on base plusieurs classes sur la même interface, on saura que toutes ces classes implémentent les méthodes définies dans l'interface. Les interfaces permettent en somme d'ajouter un peu de rigueur dans le développement.

III - Étapes de création de notre composant

Maintenant que vous avez vu sommairement les concepts liés aux classes, on peut passer à la pratique. Pour la création du composant bannière, j'ai procédé comme suit :

Étapes

Création d'un clip vide nommé « Banner ».

Cliquez sur le menu « insertion » -> « New symbol » -> « Movie clip » et nommez-le « Banner »

Liaison de la classe Banner dont le code est expliqué plus bas avec le clip « Banner »

Affichez la bibliothèque (CTRL+L) -> Cliquez avec le bouton droit sur le clip « Banner », choisissez « Linkage » -> Export for Actionscript(décochez « Export in first frame ») ->Dans la zone « AS 2.0 Class », tapez Banner (correspond au nom de la classe Banner.as)-> Cliquez sur OK

Définition du composant

Réaffichez la bibliothèque, cliquez avec le bouton droit sur le clip Banner -> Component definition -> Dans la zone « AS 2.0 Class », tapez Banner -> Cliquez sur OK -> Si tout s'est bien passé, l'aspect du clip « Banner » a changé. Une icône représentant un composant et le mot « Component » devraient apparaître à côté du clip

Exportation du composant

Réaffichez la bibliothèque, cliquez avec le bouton droit sur le clip Banner -> Export SWC file. Le répertoire dans lequel il faut stocker les composants dépend de votre système d'exploitation, pour être certain de trouver ce répertoire, faites une recherche sur le répertoire « Components ». Sur XP, ce répertoire se trouve normalement ici:
C:\Documents and Settings\votre_nom_utilisateur\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Components

Redémarrez Flash

IV - Code de la classe à associer au composant

Vous l'aurez deviné, il faut bien sûr d'abord écrire la classe avant de procéder aux étapes décrites ci-dessus.

//Liste des paramètres disponibles dans le panneau des propriétés
/*
Inspectable est une "balise" de type metadata interprétée par flash.
Dans notre exemple, la structure est toujours la même
-name représente ce qui va être affiché dans le panneau des propriétés
-variable est le nom de la variable qui stockera la valeur entrée
-type est le type de variable
-defaultValue est la valeur par défaut si l'utilisateur n'attribue pas d'autre valeur
-enumation permet d'afficher une liste de valeurs à l'utilisateur
*/
[Inspectable(name="Largeur Images", variable="imgwidth", type="Number", defaultValue=100)]
[Inspectable(name="Fichier XML", variable="xmlfile", type="String",defaultValue="")]
[Inspectable(name="Fonction associée", variable="onpressevent", type="String",defaultValue="")]
[Inspectable(name="Alpha", variable="playalpha", enumation "true,false" ,type="Boolean",defaultValue=false)]
[Inspectable(name="Fichier Son", variable="soundfile", type="String",defaultValue="")]

dynamic class Banner extends MovieClip {
public var __imageWidth:Number;
public var __xmlFile:String;
private var _XmlParser:XML;
public var __ImagesArray:Array;
public var __left:Number=0;
public var __function:String;
public var __alpha:Boolean;
public var __sound:Sound;
public var __soundFile:String;

//Constructeur
function Banner(){
this.init();
}

/*Initialisation des propriétés avec les valeurs reçues en paramètre via le panneau
des propriétés du composant.
*/
function init(){
__imageWidth=this.imgwidth;
__xmlFile=this.xmlfile;
__function=this.onpressevent;
__alpha=this.playalpha;
//Gestion du son, si le fichier son a été donné en paramètre, on le charge
__soundFile=this.soundfile;
if(__soundFile != ""){
__sound=new Sound();
__sound.onLoad=function(success){
if(success){
this.__soundOk=true;
}
}
__sound.loadSound(__soundFile,false);
}

if(__xmlFile != ""){
this.ParseXml();
}
}
/*Cette fonction parse le fichier XML afin de récupérer les chemins des images.
Elle est assez simple étant donné que la structure du fichier XML l'est
*/
private function ParseXml(){
XmlParser=new XML();
XmlParser.Owner=this;//Astuce pour lier la méthode onLoad de XML et l'objet courant
XmlParser.onLoad=function(success){
if(success){
XmlParser.Owner.__ImagesArray=new Array();
for(i=0;i<this.firstChild.childNodes.length;i++){
if(this.firstChild.childNodes[i].attributes.path != undefined){
//Ici on construit un tableau qui contiendra tous les chemins des images
XmlParser.Owner.__ImagesArray.push(this.firstChild.childNodes[i].attributes.path);
}
}
XmlParser.Owner.BuildClip();
}
}
//Instruction pour charger le fichier XML
XmlParser.load(__xmlFile);
}

private function BuildClip(){
//On parcourt notre tableau
for(i=0;i<__ImagesArray.length;i++){
//On crée un clip vide
this.createEmptyMovieClip("img"+i,i);i
//Si un nom de fonction a été donné en paramètre, il faut l'affecter à l'évènement onPress du clip
if(__function != ""){
this["img"+i].Owner=this;
this["img"+i].onPress=function(){
if(this.Owner.__sound.__soundOk){ //Si le son a été chargé
this.Owner.__sound.start();
}
eval(this.Owner.__function)(this);
}
}
//Cette partie gère la transparence de l'image selon le paramètre alpha du composant
if(__alpha){
this["img"+i].onRollOver=function(){
this._alpha=50;
}
this["img"+i].onRollOut=function(){
this._alpha=100;
}
}
/*On recrée un clip vide, car ici aussi il y a une astuce. Pour pouvoir charger l'image dans un clip et attribuer une
action à l'évènement onPress, il faut passer par deux clips vides, car le loadMovie "écrase" la méthode onPress affectée.
Donc, on crée un premier clip vide "conteneur" auquel on associe une action à onPress et, dans ce clip, on en crée un
deuxième qui contiendra l'image.*/
this["img"+i].createEmptyMovieClip("sub_img"+i,i);
with (this["img"+i]["sub_img"+i]) {
//On positionne l'image grâce au paramètre "largeur d'images" passé au composant
_x=this.__left;
_y=20;
loadMovie(this.__ImagesArray[i]);
}
__left+=__imageWidth;
}
/*Le composant étant attaché à un clip qui lui-même est lié à un scrollpane. On sait que le parent du composant
est le clip et que le parent du clip est le scrollpane. Étant donné que le Scrollpane est probablement le composant
standard le plus ennuyeux à utiliser dû à son comportement pas toujours très cohérent. J'ai été obligé d'appeler la méthode
redraw qui redessine le scrollpane après chargement de son contenu. Sans cet appel, le scroll n'affichait pas tout le contenu
chargé. De surcroît, un simple appel à redraw ne suffisait pas, il fallait absolument l'appeler via un évènement associé au
scrollpane, comme mouseMove ou mouseUP. Si vous trouvez une autre méthode, faites-moi signe :-)*/
if(this._parent._parent != undefined){
this._parent._parent.onMouseMove=function(){
this.redraw(true);
}
}

}

V - Structure du fichier XML

La structure du fichier XML est on ne peut plus simple. Pour pouvoir utiliser le composant, vous allez devoir créer votre propre fichier XML qui devra OBLIGATOIREMENT respecter cette structure :

<images>
<img path="http://stephaneey.developpez.com/cameleon.jpg"></img>
<img path="http://stephaneey.developpez.com/lemurien.jpg"></img>
<img path="http://stephaneey.developpez.com/escargot.jpg"></img>
<img path="http://stephaneey.developpez.com/cameleon.jpg"></img>
<img path="http://stephaneey.developpez.com/lemurien.jpg"></img>
<img path="http://stephaneey.developpez.com/escargot.jpg"></img>
</images>

Pour faciliter la compréhension du mécanisme, le contenu du fichier XML ci-dessus est le même que celui du fichier XML que j'ai utilisé dans la section « A quoi ressemble-t-il? »

L'attribut « path » contient l'URL où se trouve l'image à afficher et est récupéré par le composant dans la méthode « ParseXml ».

Note: pour des raisons de sécurité, Flash n'autorise pas le chargement de fichier XML ou autre se trouvant dans un autre domaine que le swf. Donc, si votre animation tourne sur http://www.monsite.com/animation.swf, le fichier xml doit aussi se trouver sur http://www.monsite.com/ ou un sous-répertoire de cette racine web.

VI - Particularité du paramètre fonction du composant

Comme nous l'avons vu plus haut, un paramètre « fonction » est associé au composant et vous permet d'exécuter votre propre fonction lorsque l'utilisateur clique sur une image.

Le composant passe l'instance du clip contenant l'image à cette fonction. Vous devrez donc déclarer un argument à celle-ci, comme montré ci-dessous.

function ma_fonction(obj){ // l'argument obj contiendra l'instance du clip contenant l'image cliquée
trace(obj);
}

Cela vous permettra d'exécuter des actions particulières sur votre clip.

VII - Intégrer ce composant dans une animation Flash

Pour intégrer le composant dans une animation Flash, il faut procéder aux étapes suivantes :

- créez un clip et nommez-le comme vous voulez ;

- insérez-y le composant (drag and drop) sur la scène, aux coordonnées x:0 et y:0 OBLIGATOIREMENT ;

- renseignez les propriétés du composant (le paramètre fonction n'est pas obligatoire) ;

- affichez la bibliothèque, sélectionnez le clip et liez-le à actionscript (clic droit->linkage) ;

- revenez sur la scène principale ou dans un autre clip et insérez-y un composant scrollpane (drag and drop) ;

- via le panneau des propriétés du scrollpane, insérez le nom de votre clip dans la propriété contentPath ;

- n'oubliez bien sûr pas de créer votre fichier XML comme expliqué en section 5 ;

Et voilà, vous pouvez lancer votre animation !

VIII - Téléchargement

- Téléchargez le fichier zip et dézippez-le sur votre machine.
- Procédez aux étapes décrites en section 3.

IX - Conclusion

Vous êtes à présent capable de créer vos propres composants ou de faire évoluer celui-ci. Afin de vous pousser à reproduire les étapes décrites en section 3, j'ai laissé intentionnellement le clip « Developpez.com. Club … » dans le composant. Si vous désirez l'enlever, il vous faudra recréer le composant. Au cas où vous le recréez, vous devrez changer une ligne de code dans la classe actionscript2. La ligne :

_y=20;

devra être remplaçée par :

_y=0;