I. Introduction▲
Dans ce chapitre, nous allons enfin aborder la pratique. En effet, nous allons coder les fonctionnalités de base de notre bibliothèque de composants ou « components framework ».
Comme nous l'avons vu précédemment (Chapitre 2 : Comment créer des composants ?), nous allons suivre chacune des étapes conseillées.
Commençons déjà par décrire quelles sont ces fonctionnalités au sein d'un CDCF (Cahier des Charges Fonctionnel).
II. Bibliothèque de composants : le CDCF▲
Nous avons déjà clairement défini dans le « Chapitre 1 : Pourquoi créer des composants graphiques ? », ce qui, pour nous, est un composant graphique.
En voici le résumé :
« Un composant est un élément qui apporte une interaction avec l'utilisateur, il est possible de le faire apparaître ou disparaître à volonté et il se doit d'être personnalisable au niveau de l'apparence. »
C'est une description courte, qui résume au niveau fonctionnel, ce que doit être composant graphique.
Les points importants d'un composant
- Le composant doit apporter une interaction avec l'utilisateur, il s'agira donc bien entendu d'un objet graphique.
- Il est possible de le faire apparaître et disparaître à volonté : en effet, un composant doit pouvoir être supprimé et ajouté à la display list (la liste d'affichage) sans aucun effort.
- Il doit être personnalisable au niveau de l'apparence : notre composant devra pouvoir changer de style graphique, et ce, de la manière la plus simple qui soit.
Notre CDCF (Cahier des Charges Fonctionnel) est certes un peu court, toutefois, nous n'avons pas besoin de plus de précisions, celles-ci seront données dans le CDCT (Cahier des Charges Technique).
III. Bibliothèque de composants : le CDCT▲
C'est la partie la plus intéressante, la description technique des fonctionnalités de base de l'ensemble de nos futurs composants, commençons sans plus tarder en reprenant le CDCT (Cahier des Charges Technique).
Le composant apporte une interaction avec l'utilisateur
Notre classe de base sera donc un objet graphique, nous choisissons d'étendre la classe graphique de base flash.display.Sprite.
Possibilité de le faire apparaître ou disparaître à volonté
En as3, nous pouvons manipuler la liste d'affichage (aussi appelée display list) avec les méthodes classiques de chaque objet graphique. Cependant, nous allons ajouter quelques fonctionnalités supplémentaires.
- Une méthode hide, qui nous permettra de « cacher » notre objet graphique en le supprimant de la display list, tout en sauvegardant son ancien objet parent dans une propriété « lastParent ».
- Un getter lastParent qui nous permettra de récupérer le dernier parent du composant.
- Une méthode show qui nous permettra de rajouter notre objet graphique à la display list de son lastParent.
Avec ces fonctionnalités communes à tous les composants, nous pouvons cacher / supprimer et montrer / ajouter un objet à la display list de manière extrêmement simplifiée, avec une seule méthode.
Personnalisable au niveau de l'apparence
Les composants doivent pouvoir être customisables, en anglais nous appelons cela le « skin » (skin = peau).
Ainsi, nous allons donc créer un objet « Skin » qui permet d'associer des valeurs de constantes à des noms de classe.
Nous enverrons ensuite cet objet « Skin » à une méthode nommée « applySkin », définie dans une interface Iskinnable. Cette interface sera implémentée par tous nos composants.
Ajout de quelques fonctionnalités supplémentaires
- Une méthode destroy, qui permet de détruire proprement notre composant.
- Une méthode resize, qui permet de redimensionner proprement notre composant.
- Une méthode onAdded qui s'exécute lorsque le composant sera ajouté à la display list d'un objet graphique, pour le premier.
- Une méthode onAddedToStage qui s'exécute lorsque le composant ou son parent sera ajouté à la display list du stage. Pour simplifier, cette méthode est appelée dès que la propriété stage du composant est disponible.
- Une méthode onRemoved qui s'exécute lorsque le composant est enlevé de la display list de son parent.
- Une méthode onRemovedFromStage qui s'exécute lorsque le composant est enlevé de la display list du stage.
- Un getter / setter de type Tooltip, nous reviendrons sur ce point plus tard, lorsque nous aborderons le chapitre relatif au composant Tooltip.
- Nous redévelopperons également le comportement d'un évènement bien pratique qui a disparu lors du passage à l'as3. L'évènement onReleaseOutside, qui s'exécute lorsque l'utilisateur relâche le clic gauche de la souris en dehors de l'objet dans lequel a été capturé le mouseDown.
IV. Conclusion▲
Nous disposons désormais des bases essentielles pour coder nos différents composants, ceux-ci hériteront tous de la classe UIComponent qui est notre classe de composant de base.
Dans le prochain chapitre, nous allons attaquer notre premier vrai composant utile, un bouton.
Sources commentées
- com.actionscriptfacile.skin.ISkinnable
- com.actionscriptfacile.skin.Skin
- com.actionscriptfacile.skin.ISkin
- com.actionscriptfacile.ui.IComponent
- com.actionscriptfacile.ui.UIComponent
Vous trouverez ci-dessous l'ensemble des classes créées. Elles sont commentées pour vous permettre de comprendre leur fonctionnement.
N'hésitez pas à poser vos questions sur le Forum AS3 DeveloppezForum AS3 Developpez.
package
com.
actionscriptfacile.
skin
{
import
com.
actionscriptfacile.
skin.
ISkin;
public
interface
ISkinnable
{
function
applySkin
(
p_skin:
ISkin ):
void
;
}
}
package
com.
actionscriptfacile.
skin
{
import
com.
actionscriptfacile.
skin.
ISkin;
import
flash.
utils.
Dictionary;
import
flash.
utils.
getDefinitionByName;
import
flash.
utils.
getQualifiedClassName;
public
class
Skin implements
ISkin
{
private
var
m_data:
Dictionary;
public
function
Skin
(
)
{
m_data =
new
Dictionary
(
);
}
public
function
setSkin
(
p_skinName:
String
,
p_skinDefinition:
Class ):
void
{
m_data[
p_skinName ]
=
p_skinDefinition;
}
public
function
getSkin
(
p_skinName:
String
) :
Class
{
return
m_data[
p_skinName ];
}
public
function
clone
(
):
ISkin
{
var
definition:
Class =
getDefinitionByName
(
getQualifiedClassName
(
this
) ) as Class;
var
skin:
ISkin =
new
definition
(
) as ISkin;
skin.
setSkins
(
m_data );
return
skin;
}
public
function
setSkins
(
p_skins:
Dictionary):
void
{
m_data =
p_skins;
}
public
function
getSkins
(
):
Dictionary {
return
m_data;
}
public
function
destroy
(
):
void
{
m_data =
null
;
delete
this
;
}
}
}
package
com.
actionscriptfacile.
skin
{
import
flash.
utils.
Dictionary;
public
interface
ISkin
{
function
setSkin
(
p_skinName:
String
,
p_skinDefinition:
Class ):
void
;
function
getSkin
(
p_skinName:
String
):
Class;
function
setSkins
(
p_skins:
Dictionary ):
void
;
function
getSkins
(
):
Dictionary;
function
clone
(
):
ISkin;
function
destroy
(
):
void
;
}
}
package
com.
actionscriptfacile.
ui
{
import
com.
actionscriptfacile.
skin.
ISkinnable;
import
flash.
display.
DisplayObjectContainer;
import
com.
actionscriptfacile.
ui.
tooltip.
Tooltip;
public
interface
IComponent extends
ISkinnable
{
function
destroy
(
):
void
;
function
hide
(
):
void
;
function
show
(
):
void
;
function
onAdded
(
):
void
;
function
onRemoved
(
):
void
;
function
onAddedToStage
(
):
void
;
function
onRemovedFromStage
(
):
void
;
function
resize
(
p_width:
Number
,
p_height:
Number
):
void
;
function
set tooltip
(
p_toolTip:
Tooltip ):
void
;
function
get
tooltip
(
):
Tooltip;
function
get
lastParent
(
):
DisplayObjectContainer;
}
}
package
com.
actionscriptfacile.
ui
{
import
com.
actionscriptfacile.
skin.
ISkin;
import
com.
actionscriptfacile.
ui.
tooltip.
Tooltip;
import
flash.
display.
DisplayObject;
import
flash.
display.
DisplayObjectContainer;
import
flash.
display.
Sprite;
import
flash.
events.
Event;
import
com.
actionscriptfacile.
ui.
IComponent;
import
flash.
events.
MouseEvent;
/**
* Classe de base de tous les composants
* @author Matthieu
*/
public
class
UIComponent extends
Sprite implements
IComponent
{
private
var
m_lastParent:
DisplayObjectContainer;
// Le dernier parent connu de l'objet
private
var
m_tooltip:
Tooltip;
// Un objet de type Tooltip
static
public
const
RELEASE_OUTSIDE:
String
=
'RELEASE_OUTSIDE'
;
// Constante utilisée pour les addEventListener
/**
* Constructeur
*/
public
function
UIComponent
(
)
{
m_lastParent =
null
;
m_tooltip =
null
;
addEventListener
(
Event.
ADDED,
addedHandler );
addEventListener
(
Event.
ADDED_TO_STAGE,
addedHandler );
addEventListener
(
Event.
REMOVED,
removeHandler );
addEventListener
(
Event.
REMOVED_FROM_STAGE,
removeHandler );
addEventListener
(
MouseEvent.
MOUSE_DOWN,
downUpHandler );
addEventListener
(
MouseEvent.
ROLL_OVER,
overOutHandler );
addEventListener
(
MouseEvent.
ROLL_OUT,
overOutHandler );
}
// events listeners
/**
*
* Cette méthode est utilisée pour afficher / cacher le tooltip si celui-ci est défini.
*
* @param e Un objet de type MouseEvent
*/
private
function
overOutHandler
(
e:
MouseEvent):
void
{
if
(
m_tooltip ==
null
)
{
return
;
}
if
(
e.
type
==
MouseEvent.
ROLL_OUT )
{
m_tooltip.
hide
(
);
}
else
{
m_tooltip.
show
(
);
}
}
/**
* @private utilisée pour détecter les RELEASE OUTSIDE
* @param e
*/
private
function
downUpHandler
(
e:
MouseEvent):
void
{
if
(
e.
type
==
MouseEvent.
MOUSE_DOWN )
{
/*
* Si on appuie sur le clic de la souris alors on cherche à détecter le moment
* où on la relâchera que l'on soit sur l'objet ou non.
*
* */
stage.
addEventListener
(
MouseEvent.
MOUSE_UP,
downUpHandler );
stage.
addEventListener
(
MouseEvent.
MOUSE_UP,
downUpHandler,
true
);
}
else
{
/*
* Si la souris est relâchée, nous n'avons plus besoin d'écouter les évènements adéquats.
* Nous vérifions ensuite que la souris ne se trouvait pas sur le composant à ce moment-là
* et on dispatch un évènement.
* */
stage.
removeEventListener
(
MouseEvent.
MOUSE_UP,
downUpHandler );
stage.
removeEventListener
(
MouseEvent.
MOUSE_UP,
downUpHandler,
true
);
if
(
!
hitTestPoint
(
e.
stageX,
e.
stageY ,
false
) )
{
dispatchEvent
(
new
Event
(
RELEASE_OUTSIDE,
true
,
true
) );
}
}
}
/**
*
* Détecte les évènements de type Event.ADDED et Event.ADDED_TO_STAGE et se charge d'appeler
* les méthodes onAdded ou onAddedToStage.
*
* @param e évènements de type Event
*/
private
function
addedHandler
(
e:
Event ):
void
{
if
(
parent !=
null
)
{
m_lastParent =
parent;
}
if
(
e.
type
==
Event.
ADDED )
{
onAdded
(
);
}
else
{
onAddedToStage
(
);
}
}
/**
*
* Détecte les évènements de type Event.REMOVED et Event.REMOVED_FROM_STAGE et se charge d'appeler
* les méthodes onRemoved ou onRemovedFromStage.
*
* @param e évènements de type Event
*/
private
function
removeHandler
(
e:
Event ):
void
{
if
(
parent !=
null
)
{
m_lastParent =
parent;
}
if
(
e.
type
==
Event.
REMOVED )
{
onRemoved
(
);
}
else
{
onRemovedFromStage
(
);
}
}
// fonctions publiques
/**
* Détruit proprement le composant
*/
public
function
destroy
(
):
void
{
// on cherche à sortir de la display list du parent
if
(
parent !=
null
&&
parent.
contains
(
this
) )
{
parent.
removeChild
(
this
);
}
// on supprime proprement tous les objets de note display list
while
(
numChildren >
0
)
{
var
child:
DisplayObject =
removeChildAt
(
0
);
child =
null
;
}
// on passe la propriété lastParent à null
m_lastParent =
null
;
// Enfin, on détruit tous les event listeners
removeEventListener
(
Event.
ADDED,
addedHandler );
removeEventListener
(
Event.
ADDED_TO_STAGE,
addedHandler );
removeEventListener
(
Event.
REMOVED,
removeHandler );
removeEventListener
(
Event.
REMOVED_FROM_STAGE,
removeHandler );
removeEventListener
(
MouseEvent.
MOUSE_DOWN,
downUpHandler );
removeEventListener
(
MouseEvent.
ROLL_OVER,
overOutHandler );
removeEventListener
(
MouseEvent.
ROLL_OUT,
overOutHandler );
stage.
removeEventListener
(
MouseEvent.
MOUSE_UP,
downUpHandler );
stage.
removeEventListener
(
MouseEvent.
MOUSE_UP,
downUpHandler,
true
);
delete
this
;
}
/**
* Supprime le composant de la display list de son lastParent
*/
public
function
hide
(
):
void
{
if
(
parent !=
null
&&
parent.
contains
(
this
) )
{
m_lastParent =
parent;
parent.
removeChild
(
this
);
}
}
/**
* Ajoute le composant à la display list de son lastParent
*/
public
function
show
(
):
void
{
visible
=
true
;
if
(
m_lastParent ==
null
)
return
;
m_lastParent.
addChild
(
this
);
}
// fonctions destinées à être overridées
/**
* Est exécutée lorsque le composant est ajouté à la display list d'un DisplayObjectContainer,
* cette méthode prend tout son sens dans le cas d'un override.
*/
public
function
onAdded
(
):
void
{
}
/**
* Est exécutée lorsque le composant est supprimé de la display list d'un DisplayObjectContainer,
* cette méthode prend tout son sens dans le cas d'un override.
*/
public
function
onRemoved
(
):
void
{
}
/**
* Est exécutée lorsque le composant est ajouté à la display list du stage,
* cette méthode prend tout son sens dans le cas d'un override.
*/
public
function
onAddedToStage
(
):
void
{
}
/**
* Est exécutée lorsque le composant est supprimé de la display list du stage,
* cette méthode prend tout son sens dans le cas d'un override.
*/
public
function
onRemovedFromStage
(
):
void
{
}
/**
* Fonction qui sert à réceptionner et appliquer une skin au composant,
* cette méthode prend tout son sens dans le cas d'un override.
*
* @param p_skin Objet qui implémente l'interface ISkin @see
*/
public
function
applySkin
(
p_skin:
ISkin):
void
{
}
/**
* Fonction qui sert à changer la taille d'un composant de manière propre,
* cette méthode prend tout son sens dans le cas d'un override.
*
* @param p_width nouvelle largeur du composant
* @param p_height nouvelle hauteur du composant
*/
public
function
resize
(
p_width:
Number
,
p_height:
Number
):
void
{
}
// getters / setters
/**
* Définit un objet de type Tooltip
*/
public
function
set tooltip
(
p_toolTip:
Tooltip):
void
{
m_tooltip =
addChild
(
p_toolTip ) as Tooltip;
m_tooltip.
hide
(
);
}
/**
* Retourne le tooltip du composant
*/
public
function
get
tooltip
(
):
Tooltip {
return
m_tooltip;
}
/**
* Renvoie le dernier parent du composant.
*/
public
function
get
lastParent
(
):
DisplayObjectContainer{
return
m_lastParent;
}
}
}
V. Remerciements/Téléchargements▲
Je tiens ici à remercier La Rédactrice Kalyparker pour la mise au gabarit de l'article original au format Developpez.com.
Merci beaucoup à l'équipe Developpez.com de contribuer à la diffusion du Framework ActionScript-Facile.
TéléchargezTéléchargez le Framework AS3 Facile l'ensemble des classes commentées du Framework AS3 FacileTéléchargez le Framework AS3 Facile (avec le code source et les exemples de tous les Composants AS3).