Bien le bonjour,
Après quelques temps d'absence indépendants de ma volonté, je me suis remis un peu au taff ^^ un ptit projet sympa à mon goût, un jeu de tarot ^^
Pour ce jeu, j'avais envie d'ajouter un élément me permettant de faire des actions pendant le jeu... j'ai donc voulu faire une barre de menu horizontal (après, si vous le voulez vertical, y a qu'à revoir la création des rectangles ^^)
Attention, cette classe n'est qu'un début, je suis amené à la modifier, et ce sans la remettre ici... mais pour l'instant, elle semble fonctionner correctement à mon goût 
Ce que permet de faire la classe
Elle permet :
- d'afficher un rectangle horizontal, d'une couleur voulue, de la taille voulue, à l'endroit voulu
- d'insérer des entrées de menus (style Fichier, Edition, etc)
- d'insérer des sous menus aux menus ci-dessus (style Fichier -> Imprimer)
- d'exécuter par la classe appelante des fonctions qu'elle aura définie elle même
- de désactiver/activer à la volée des entrées de sous menus (pour permettre de dire qu'une option n'est pas dispo dans certains cas par exemple)
Lorsque vous cliquez sur un menu n'ayant pas de sous menu, la méthode correspondante est utilisée.
Lorsque vous cliquez sur un menu ayant au moins un sous menu, la liste des sous menu correspondant est affichée avec un petit effet visuel (Tween).
Lorsque vous cliquez sur un sous menu, la méthode correspondante est utilisée et le sous menu est refermé.
Lorsque vous DOUBLE-CLIQUEZ dans le vide, le sous menu ouvert est refermé.
Lorsque vous cliquez sur un autre menu que celui qui est déroulé, celui déjà déroulé est refermé.
La classe :
package outils
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.display.Shape;
import flash.display.Graphics;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.events.MouseEvent;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
public class MenuHorizontal extends MovieClip
{
public var scene:Stage;
private var posXmenu:int = 0; // en px
private var posYmenu:int = 0; // en px
private var hauteurMenu:int = 20; // en px
private var largeurMenu:int = 200; // en px
private var couleurFondMenu:uint = 0xDEDEDE; // Gris
private var rectangleFond:Shape;
private var rectangleMenuDeroule:Shape;
private var entreesMenu:Array;
private var entreesSousMenu:Array;
private var menusAderouler:Array;
private var menusSelectionne:Array;
private var fonctionAappelerMenu:Function;
private var fonctionsAappelerSousMenu:Array;
private var fonctionAappelerSousMenu:Function;
private var listeSousMenusAffiches:Array;
private var tabIndicesSousMenuAafficher:Array;
private var listeSousMenusDesactives:Array;
private var tweenRect:Tween;
private var bOnVeutDerouler:Boolean;
private var nomMenuDeroule:String = "";
private var formatEntreesActivees:TextFormat;
private var formatEntreesDesactivees:TextFormat;
public function MenuHorizontal(scene:Stage, hauteurMenu:int = 0, largeurMenu:int = 0,
couleurFondMenu:uint = 0, posXmenu:int = 0, posYmenu:int = 0)
{
this.scene = scene;
if(hauteurMenu > 0)
setHauteurMenu(hauteurMenu);
if(largeurMenu > 0)
setLargeurMenu(largeurMenu);
if(largeurMenu > 0)
setCouleurFondMenu(couleurFondMenu);
setPosXmenu(posXmenu);
setPosYmenu(posYmenu);
entreesMenu = new Array();
entreesSousMenu = new Array();
menusAderouler = new Array();
fonctionsAappelerSousMenu = new Array();
listeSousMenusDesactives = new Array();
formatEntreesDesactivees = new TextFormat();
formatEntreesDesactivees.color = 0xC0C0C0;
formatEntreesActivees = new TextFormat();
formatEntreesActivees.color = 0x000000;
}
public function addNewMenuItem(nomItem:String, nouvelItem:String,
fonctionAlancer:Function = null):void
{
entreesMenu.push(new Array(nomItem, nouvelItem, fonctionAlancer));
}
public function addNewSubMenuItem(nomItemParent:String, nomSubItem:String,
nouveauSubItem:String, fonctionAlancer:Function = null):void
{
entreesSousMenu.push(new Array(nomItemParent, nomSubItem, nouveauSubItem, fonctionAlancer));
}
public function afficherMenu():void
{
dessinerFondMenu();
dessinerEntreesMenu();
}
private function dessinerFondMenu():void
{
rectangleFond = new Shape();// Instance de l'objet d'affichage
// Le rectangle sera rempli de la couleur prédéfinie
rectangleFond.graphics.beginFill(couleurFondMenu);
//Un contour de 2 pixels et de couleur noire est utilisé
rectangleFond.graphics.lineStyle(1, 0x000000);
// dessin du rectangle avec la méthode drawRect(x, y, width, height)
rectangleFond.graphics.drawRect(0, 0, largeurMenu - 1, hauteurMenu);
// Positionnement et affichage du rectangle dans la séquence
rectangleFond.x = posXmenu;
rectangleFond.y = posYmenu;
scene.addChild(rectangleFond);
}
private function dessinerEntreesMenu():void
{
var iNbEntreesAdessiner:int = entreesMenu.length;
var formatEntrees:TextFormat = new TextFormat();
formatEntrees.leftMargin = 10;
var posXentreePrecedente:int = posXmenu;
var largeurEntreePrecedente:int = 0;
for(var i:int = 0 ; i < iNbEntreesAdessiner ; i++)
{
var containerNewEntry:MovieClip = new MovieClip();
var newEntry:TextField = new TextField();
newEntry.text = entreesMenui1;
newEntry.height = hauteurMenu;
newEntry.name = entreesMenui0;
newEntry.selectable = false;
newEntry.setTextFormat(formatEntrees);
containerNewEntry.buttonMode = true;
containerNewEntry.mouseChildren = false;
containerNewEntry.name = entreesMenui0;
containerNewEntry.x = posXentreePrecedente + largeurEntreePrecedente;
containerNewEntry.y = posYmenu;
containerNewEntry.addChild(newEntry);
scene.addChild(containerNewEntry);
posXentreePrecedente = newEntry.x;
largeurEntreePrecedente = newEntry.width;
// On traite les menu ici
if(entreesMenui2 != null) // On veut lancer une fonction ?
{
fonctionAappelerMenu = entreesMenui2;
containerNewEntry.addEventListener(MouseEvent.CLICK, appelerFonctionClasseAppelante);
}
else
{
// Pas de fonction ? Alors il faut dérouler le sous-menu associé
menusAderouler.push(entreesMenui0); // Identifié par son nom
containerNewEntry.addEventListener(MouseEvent.CLICK, deroulerMenu);
}
}
}
private function appelerFonctionClasseAppelante(e:MouseEvent):void
{
fonctionAappelerMenu.call();
}
private function deroulerMenu(e:MouseEvent):void
{
bOnVeutDerouler = true;
// Si on tente de dérouler le même menu qui l'est déjà, on le referme seulement
if(nomMenuDeroule != e.target.name)
{
effacerSousMenu();
nomMenuDeroule = e.target.name;
// On recherche les nouveaux sous menu à afficher
var iTailleSousMenuTotal:int = entreesSousMenu.length;
var iTailleMenusAderouler:int = menusAderouler.length;
tabIndicesSousMenuAafficher = new Array();
for(var j:int = 0 ; j < iTailleMenusAderouler ; j++)
{
for(var i:int = 0 ; i < iTailleSousMenuTotal ; i++)
{
if(entreesSousMenui0 == menusAderoulerj
&& e.target.name == entreesSousMenui0)
{
tabIndicesSousMenuAafficher.push(i);
}
}
}
var iTailleSousMenuAafficher:int = tabIndicesSousMenuAafficher.length;
rectangleMenuDeroule = new Shape();
rectangleMenuDeroule.graphics.beginFill(couleurFondMenu);
rectangleMenuDeroule.graphics.lineStyle(1, 0x000000);
rectangleMenuDeroule.graphics.drawRect(0, 0, largeurMenu, hauteurMenu * iTailleSousMenuAafficher);
rectangleMenuDeroule.width = 100;
rectangleMenuDeroule.x = e.target.x;
rectangleMenuDeroule.y = posYmenu + hauteurMenu;
scene.addChild(rectangleMenuDeroule);
tweenRect = new Tween(Object(rectangleMenuDeroule), "height", None.easeNone, 0,
hauteurMenu * iTailleSousMenuAafficher, .2, true);
tweenRect.addEventListener(TweenEvent.MOTION_FINISH, doNextTween);
}
else
effacerSousMenu();
}
function doNextTween(e:TweenEvent):void
{
if(rectangleMenuDeroule != null)
{
tweenRect.removeEventListener(TweenEvent.MOTION_FINISH, doNextTween);
listeSousMenusAffiches = new Array();
var iTailleSousMenuAafficher:int = tabIndicesSousMenuAafficher.length;
// On affiche les entrées de sous menu dans le rectangle
for(var i:int = 0 ; i < iTailleSousMenuAafficher ; i++)
{
var containerTxtFieldSousMenu:MovieClip = new MovieClip();
var txtFieldSousMenu:TextField = new TextField();
txtFieldSousMenu.height = hauteurMenu;
txtFieldSousMenu.width = rectangleMenuDeroule.width;
txtFieldSousMenu.text = entreesSousMenutabIndicesSousMenuAafficher[i]2;
txtFieldSousMenu.selectable = false;
containerTxtFieldSousMenu.x = rectangleMenuDeroule.x + 5;
containerTxtFieldSousMenu.y = rectangleMenuDeroule.y + (i * hauteurMenu) + 2;
// On utilise name pour stocker la fonction à appeler en cas de clic
containerTxtFieldSousMenu.name = entreesSousMenutabIndicesSousMenuAafficher[i]1;
containerTxtFieldSousMenu.addChild(txtFieldSousMenu);
scene.addChild(containerTxtFieldSousMenu);
listeSousMenusAffiches.push(containerTxtFieldSousMenu);
// Si le sous-menu n'est pas désactivé
if(listeSousMenusDesactives.indexOf(containerTxtFieldSousMenu.name) == -1)
{
containerTxtFieldSousMenu.buttonMode = true;
containerTxtFieldSousMenu.mouseChildren = false;
// On permet les clic
containerTxtFieldSousMenu.addEventListener(MouseEvent.CLICK, clicSurSousMenu);
}
else
{
// Non seulement nous n'avons pas autorisé les clics, mais en plus, on le grise
txtFieldSousMenu.setTextFormat(formatEntreesDesactivees);
}
}
scene.doubleClickEnabled = true;
scene.addEventListener(MouseEvent.DOUBLE_CLICK, fermerSousMenu);
}
bOnVeutDerouler = false;
}
private function clicSurSousMenu(e:MouseEvent):void
{
// A partir du name, on va chercher dans le tableau des sous menus
var iTailleSousMenuTotal:int = entreesSousMenu.length;
var iTailleMenusAderouler:int = menusAderouler.length;
var tabIndicesSousMenuAafficher:Array = new Array();
var i:int;
fonctionAappelerSousMenu = null;
for(var j:int = 0 ; j < iTailleMenusAderouler ; j++)
{
for(i = 0 ; i < iTailleSousMenuTotal ; i++)
{
if(entreesSousMenui0 == menusAderoulerj
&& entreesSousMenui1 == e.target.name)
{
fonctionAappelerSousMenu = entreesSousMenui3;
break;
}
}
if(fonctionAappelerSousMenu != null)
break;
}
// On efface le sous menu, et les textfield
effacerSousMenu();
// On lance l'action associée au sous menu choisi
if(fonctionAappelerSousMenu != null)
fonctionAappelerSousMenu.call();
}
private function fermerSousMenu(e:MouseEvent):void
{
effacerSousMenu();
}
private function effacerSousMenu():void
{
nomMenuDeroule = "";
if(listeSousMenusAffiches != null)
{
var iTailleSousMenusAffiches:int = listeSousMenusAffiches.length;
for(var i:int = 0 ; i < iTailleSousMenusAffiches ; i++)
{
scene.removeChild(listeSousMenusAffichesi);
}
listeSousMenusAffiches = null;
tweenRect = new Tween(Object(rectangleMenuDeroule), "height", None.easeNone,
rectangleMenuDeroule.height, 0, .2, true);
tweenRect.addEventListener(TweenEvent.MOTION_FINISH, doNextTweenEffacerSousMenu);
}
}
function doNextTweenEffacerSousMenu(e:TweenEvent):void
{
tweenRect.removeEventListener(TweenEvent.MOTION_FINISH, doNextTweenEffacerSousMenu);
// Si on a demandé au préalable de dérouler un menu, on ne met pas à null, car il a déjà été recréé
if(!bOnVeutDerouler)
{
scene.removeChild(rectangleMenuDeroule);
if(scene.hasEventListener(MouseEvent.CLICK))
scene.removeEventListener(MouseEvent.CLICK, fermerSousMenu);
rectangleMenuDeroule = null;
}
}
public function enableEntreeSousMenu(nomSousMenu:String = null, enable:Boolean = false):void
{
var i:int;
// Si nomSousMenu est renseigné, on veut désactiver un sous menu
if(nomSousMenu != null)
{
var iTailleSousMenuTotal:int = entreesSousMenu.length;
for(i = 0 ; i < iTailleSousMenuTotal ; i++)
{
if(entreesSousMenui1 == nomSousMenu)
{
if(!enable)
{
// On l'ajoute donc à la liste des sous menus désactivés
listeSousMenusDesactives.push(nomSousMenu);
}
else
{
// On le supprime de la liste
if(listeSousMenusDesactives.indexOf(nomSousMenu) !== -1)
listeSousMenusDesactives.splice(listeSousMenusDesactives.indexOf(nomSousMenu), 1);
}
}
}
}
}
public function setHauteurMenu(hauteurMenu):void
{
if(hauteurMenu > 0)
this.hauteurMenu = hauteurMenu;
}
public function getHauteurMenu():int
{
return hauteurMenu;
}
public function setLargeurMenu(largeurMenu):void
{
if(largeurMenu > 0)
this.largeurMenu = largeurMenu;
}
public function getLargeurMenu():int
{
return largeurMenu;
}
public function setCouleurFondMenu(couleurFondMenu):void
{
if(couleurFondMenu > 0)
this.couleurFondMenu = couleurFondMenu;
}
public function getCouleurFondMenu():int
{
return couleurFondMenu;
}
public function setPosXmenu(posXmenu):void
{
this.posXmenu = posXmenu;
}
public function getPosXmenu():int
{
return posXmenu;
}
public function setPosYmenu(posYmenu):void
{
this.posYmenu = posYmenu;
}
public function getPosYmenu():int
{
return posYmenu;
}
}
}
L'utilisation par l'exemple :
import outils.MenuHorizontal; // L'import, si la classe est dans le dossier outils, lui même au même niveau que la classe l'important...
public var menu:MenuHorizontal; // La déclaration de l'attribut de la classe appelante
/* On affiche le menu horizontal en haut de l'écran */
menu = new MenuHorizontal(stage, 20, stage.stageWidth, 0xDEDEDE, 0, 0);
menu.addNewMenuItem("actions", "Actions"); // Un menu "Actions"
// Lorsque l'on clique sur "Actions", on déroule et on affiche une entrée "Nouveau" qui exécutera la méthode clicNouvellePartie
menu.addNewSubMenuItem("actions", "nouveau", "Nouveau", clicNouvellePartie);
//menu.addNewSubMenuItem("actions", "bla", "Bla", clicNouvellePartie); // Pour une autre entrée du menu Actions ?
menu.addNewMenuItem("aide", "Aide", clicOuvrirAide); // Et un menu "Aide"
menu.afficherMenu(); // On affiche le menu à l'écran
// On désactive cette entrée (elle sera grisée et non cliquable
menu.enableEntreeSousMenu("nouveau", false);
// Pour réactiver
//menu.enableEntreeSousMenu("nouveau", true); // Ce qui aura pour effet de réécrire en noir, et de rendre cliquable
Et voici les méthodes appelée :
/* Méthode appelée au clic sur un menu */
public function clicOuvrirAide():void
{
trace("on ouvre l'aide");
}
/* Méthode appelée au clic sur un menu */
public function clicNouvellePartie():void
{
lancerPartie();
}
Notes finales :
Je pense avoir un outil assez intéressant pour faire comme un menu standard... à vous de jouer si vous souhaitez l'améliorer... faites moi savoir ce que vous aurez fait !