Blog technique

Du code et du code

http://www.trouvelecode.com

http://www.trouvelecode.com : Trouve le code et gagne un cadeau !

Sorti début septembre, je commence simplement à faire la promotion, ayant préféré le parfaire avant de le faire connaitre.

Le but du jeu est simple : après s'être inscrit, vous pouvez tenter de trouver un code de longueur variable. Vous avez droit à un essai à intervalle régulier (pour commencer, j'ai fixé toutes les 7 minutes). Après validation de votre proposition, le site vous indique le nombre d'éléments corrects trouvés (à la mastermind), ainsi que le premier caractère correct (en partant du principe que si vous saisissez un code xtgF24dgfFER et que le code est gfdFed4dsg, le site vous dira que vous avez 3 éléments juste (F en 4ième position, 4 en 6ième et d en 7ième) et que le premier caractère correct est le F en 4ième position.

Le site est financé par de la publicité Google AdSense (premier test pour moi, ne sachant pas exactement ce que cela peut rapporter en vrai), et par un système de micropaiement Rentabiliweb. Ce dernier permet au joueur le souhaitant d'obtenir un caractère déterminé aléatoirement avec sa position dans le code à trouver. A noter d'ailleurs que si le joueur envoie 2 SMS pour un code à trouver, il n'aura jamais 2 fois le même indice (et heureusement non ? ^^) Informations complémentaires

Voici donc pour rappel le lien vers le site : Cliquez ici pour vous inscrire ou pour jouer le cas échéant. Merci de me faire part de vos remarques, trouvaille de bug, de vos critiques ou même de vos compliments.

Carrousel horizontal

Ca faisait **encore** longtemps que je n'avais pas posté de nouveauté. Ce n'est est pas une, mais je ne trouvais pas ce que je cherchais sur le net, correspondant exactement à mon envie.

Bref, voici un carrousel horizontal, avec 1 zone sensible de chaque côté permettant de faire défiler les icônes affichées s'il y en a plus que la largeur le permet. Au survol sur un icône, un descriptif est affiché, et un clic dessus permet d'appeler une page web.

Pour cette classe AS3, j'utilise une classe de MassLoad, qui permet de précharger des médias avant de commencer quoique ce soit... Cela me permet dans ce cas de précharger les images dont j'ai besoin, et d'avoir un préloader (textuel). Vous pourrez le trouver à cet endroit : avec un joli tuto pour l'utilisation ;-)

La classe

package
{
	import flash.display.MovieClip;
	import flash.display.Stage;
	import outils.ch.capi.net.CompositeMassLoader;
	import outils.ch.capi.net.ILoadableFile;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.NetStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.AsyncErrorEvent;
	import flash.events.ProgressEvent;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.ui.Mouse;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;

	public class Carrousel extends MovieClip
	{
		public var scene:Stage;
		
		public var loader:CompositeMassLoader;
		public var texteChargement:TextField;
		
		// Données recues en flashvars
		public var urlServeur:String = "http://127.0.0.1/url_de_developpement_du_site/";
               public var cheminImagesCarrousel = "/images/carrousel/";
               // Le premier param est l'image de fond du carrousel, qui ne bouge pas
               // La suite représente : image représentant l'icône à afficher | 
               // descriptif lors du survol de l'icône | 
               // lien vers lequel on ira lors du clic sur l'icône
		public var listeFichiersAchargerStr:String = "fond.jpg"
				+ "#jeu_1.png|Jeu numéro 1|jeu_chambouletout.php"
				+ "#jeu_2.png|Jeu numéro 2|jeu_tireficelles.php"
				+ "#jeu_3.png|Jeu numéro 3|jeu_chambouletout.php"
				+ "#jeu_4.png|Jeu numéro 4|jeu_chambouletout.php"
				+ "#jeu_5.png|Jeu numéro 5|jeu_chambouletout.php"
				+ "#jeu_6.png|Jeu numéro 6|jeu_chambouletout.php"
				+ "#jeu_7.png|Jeu numéro 7|jeu_chambouletout.php"
				+ "#jeu_8.png|Jeu numéro 8|jeu_chambouletout.php"
				+ "#jeu_9.png|Jeu numéro 9|jeu_chambouletout.php";
		public var listeFichiersAcharger:Array;
		
		const LARGEUR_IMAGES = 100; // en px
		const LARGEUR_ZONES_SENSIBLES = 20; // en px
		const OFFSET_AFFICHAGE_ICONES_COTES = 20; // en px
		
		public var fondMc:MovieClip;
		public var zoneMasqueDefilement:MovieClip;
		public var zoneSensibleGauche:MovieClip;
		public var zoneSensibleDroite:MovieClip;
		public var bDeplacementGauche:Boolean;
		public var bDeplacementDroite:Boolean;
		public var iPasDefilement:int = 10;
		public var positionXmaxiDroite:int;
		public var nomIconeSurvole:TextField;

		public function Carrousel()
		{
			scene = stage;
			
			texteChargement = new TextField();
			texteChargement.x = 0;
			texteChargement.y = 0;
			texteChargement.width = 150;
			texteChargement.text = "Chargement des éléments...";
			scene.addChild(texteChargement);
			
			var urlServeurParam:String = urlServeur;
			if(loaderInfo.parameters.urlServeur != undefined)
				urlServeurParam = String(loaderInfo.parameters.urlServeur);
			urlServeur = urlServeurParam;
			var cheminImagesCarrouselParam:String = cheminImagesCarrousel;
			if(loaderInfo.parameters.cheminImages != undefined)
			        cheminImagesCarrouselParam = String(loaderInfo.parameters.cheminImages);
			cheminImagesCarrousel = cheminImagesCarrouselParam;
			
			var listeFichiersParam:String = listeFichiersAchargerStr;
			if(loaderInfo.parameters.listeFichiersAchargerStr != undefined)
				listeFichiersParam = String(loaderInfo.parameters.listeFichiersAchargerStr);
			listeFichiersAchargerStr = listeFichiersParam;
			
			listeFichiersAcharger = new Array();
			// On découpe le tout pour le mettre dans le tableau qui va bien format : 
                      // nom_img|detail|url_au_clic#nom_img|detail|url_au_clic
			var aListeComplet:Array = listeFichiersAchargerStr.split("#");
			var iNbImg:int = aListeComplet.length;
			var i:int;
			if(aListeComplet.length > 0)
			{
				for(i = 0 ; i < iNbImg ; i++)
				{
					var aDetailsDecoupes:Array = aListeCompleti.split("|");

					if(aDetailsDecoupes.length > 0)
						listeFichiersAcharger.push(new Array(aDetailsDecoupes0, 
                                                                                                 aDetailsDecoupes1, 
                                                                                                 aDetailsDecoupes2));
				}
			}
			else
			{
				texteChargement.text = "Aucune image à charger...";
				return;
			}
			
                       // Permet d'afficher le descriptif de l'icône survolée
			nomIconeSurvole = new TextField();
			nomIconeSurvole.width = stage.stageWidth - 1;
			nomIconeSurvole.selectable = false;
			nomIconeSurvole.multiline = false;
			
			var nomTextFormat:TextFormat = new TextFormat();
			nomTextFormat.align = TextFormatAlign.CENTER;
			nomIconeSurvole.defaultTextFormat = nomTextFormat;
			
			//création du loader
			loader = new CompositeMassLoader();
			loader.massLoader.parallelFiles = 1; // Un fichier loadé à la fois
			 
			//ajout des fichiers dans la liste de chargement
			iNbImg = listeFichiersAcharger.length;
			for(i = 0 ; i < iNbImg ; i++)
			{
				// On indique les fichiers à pré charger
                               loader.addFile(urlServeur + cheminImagesCarrousel + listeFichiersAchargeri0);
			}
			
			loader.massLoader.addEventListener(ProgressEvent.PROGRESS, p);
			loader.massLoader.addEventListener(Event.COMPLETE, l);
			loader.start();
		}
		
		public function l(evt:Event):void
		{
			scene.removeChild(texteChargement);
			
			var listeLoaderCharges:Array = new Array();
			var i:int;
			
			var iNbImg:int = listeFichiersAcharger.length;
			for(i = 0 ; i < iNbImg ; i++)
			{
				var file:ILoadableFile = loader.getFileAt(i); // On récupère chaque image chargée
				var ImgLoadee:Loader = file.getData("flash.display.Loader");
				listeLoaderCharges.push(ImgLoadee);
			}
			
			scene.addChild(listeLoaderCharges0); // On charge le fond du carrousel
			
			fondMc = new MovieClip();
			scene.addChild(fondMc);

			var offset:int = OFFSET_AFFICHAGE_ICONES_COTES;
			for(i = 1 ; i < iNbImg ; i++)
			{
				var jeuMc:MovieClip = new MovieClip();
				jeuMc.addChild(listeLoaderChargesi);
				
				jeuMc.x = offset + (i - 1) * LARGEUR_IMAGES;
				jeuMc.name = String(i);
				offset = 0; // On n'utilise l'offset gauche qu'au premier coup.

				jeuMc.buttonMode = true;
				jeuMc.addEventListener(MouseEvent.ROLL_OVER, zoomJeu);
				jeuMc.addEventListener(MouseEvent.ROLL_OUT, zoomJeu);
				jeuMc.addEventListener(MouseEvent.CLICK, choixJeu);
				fondMc.addChild(jeuMc);
			}
			
			positionXmaxiDroite = -((iNbImg - 1) * LARGEUR_IMAGES);
			
			// On pose un masque par dessus le fond
			zoneMasqueDefilement = new MovieClip();
			zoneMasqueDefilement.graphics.beginFill(0xFFFFFF);
			zoneMasqueDefilement.graphics.drawRect(0, 0, 
									stage.stageWidth - (LARGEUR_ZONES_SENSIBLES * 2),
									stage.stageHeight);
			zoneMasqueDefilement.x = LARGEUR_ZONES_SENSIBLES;
			scene.addChild(zoneMasqueDefilement);
			fondMc.mask = zoneMasqueDefilement;
			
			// Gestion des zones sensibles pour le défilement
			zoneSensibleGauche = new MovieClip();
			zoneSensibleGauche.graphics.beginFill(0xFFFFFF);
			zoneSensibleGauche.graphics.drawRect(0, 0, LARGEUR_ZONES_SENSIBLES, stage.stageHeight);
			zoneSensibleGauche.alpha = .2;
			zoneSensibleGauche.name = "zoneGauche";
			scene.addChild(zoneSensibleGauche);
			
			zoneSensibleGauche.addEventListener(MouseEvent.ROLL_OVER, rollOverZoneSensible);
			zoneSensibleGauche.addEventListener(MouseEvent.ROLL_OUT, rollOutZoneSensible);
			
			zoneSensibleDroite = new MovieClip();
			zoneSensibleDroite.graphics.beginFill(0xFFFFFF);
			zoneSensibleDroite.graphics.drawRect(0, 0, LARGEUR_ZONES_SENSIBLES, stage.stageHeight);
			zoneSensibleDroite.alpha = .2;
			zoneSensibleDroite.x = stage.stageWidth - zoneSensibleDroite.width;
			zoneSensibleDroite.name = "zoneDroite";
			scene.addChild(zoneSensibleDroite);
			
			zoneSensibleDroite.addEventListener(MouseEvent.ROLL_OVER, rollOverZoneSensible);
			zoneSensibleDroite.addEventListener(MouseEvent.ROLL_OUT, rollOutZoneSensible);
			
			stage.addEventListener(Event.ENTER_FRAME, moveCarrousel);
		}
		
		private function rollOverZoneSensible(e:MouseEvent):void
		{
			if(e.target.name == "zoneGauche")
			{
				bDeplacementGauche = true;
				bDeplacementDroite = false;
			}
			else
			{
				bDeplacementGauche = false;
				bDeplacementDroite = true;
			}
		}
		
		private function rollOutZoneSensible(e:MouseEvent):void
		{
			bDeplacementGauche = false;
			bDeplacementDroite = false;
		}
		
		private function moveCarrousel(e:Event):void
		{
			if(bDeplacementGauche && (fondMc.x + iPasDefilement) <= 0)
				fondMc.x += iPasDefilement;
			else if(bDeplacementDroite 
			&& )
				fondMc.x -= iPasDefilement;
		}
		
		private function zoomJeu(e:MouseEvent):void
		{
			var iRatioZoom:int = 1;
			if(e.type == MouseEvent.ROLL_OVER)
			{
				e.target.scaleX = 1 + (iRatioZoom / 10);
				e.target.scaleY = 1 + (iRatioZoom / 10);
				e.target.x -= (iRatioZoom * 10) / 2;
				e.target.y -= (iRatioZoom * 10) / 2;
				
				// On utilise un textfield qui contiendra le descriptif de l'icone
				nomIconeSurvole.text = listeFichiersAchargerint(e.target.name)1;
				nomIconeSurvole.border = true;
				nomIconeSurvole.borderColor = 0x000000;
				nomIconeSurvole.background = true;
				nomIconeSurvole.backgroundColor = 0xFFFFFF;
				nomIconeSurvole.height = 20;
				nomIconeSurvole.x = stage.stageWidth / 2 - nomIconeSurvole.width / 2;
				nomIconeSurvole.y = stage.stageHeight - nomIconeSurvole.height - 1;
				
				scene.addChild(nomIconeSurvole);
			}
			else
			{
				e.target.scaleX = 1;
				e.target.scaleY = 1;
				e.target.x += (iRatioZoom * 10) / 2;
				e.target.y += (iRatioZoom * 10) / 2;
				
				scene.removeChild(nomIconeSurvole);
			}
		}
		
		private function choixJeu(e:MouseEvent):void
		{
			var request:URLRequest = new URLRequest(urlServeur + listeFichiersAchargerint(e.currentTarget.name)2);
			try 
			{
				navigateToURL(request, '_self'); // second argument is target
			} 
			catch (e:Error) 
			{
				trace("Error occurred!");
			}
		}
		
		public function p(evt:ProgressEvent):void
		{
			texteChargement.text = loader.massLoader.loadInfo.percentLoaded + " %";
		}
	}
}

Utilisation

On créé un fla avec une scène de sa convenance (largeur 600 et hauteur 110 par exemple), la classe de document étant Carrousel...

Un Ctrl+Entrée est c'est tout bon (pour peu que les noms indiqués existent à l'endroit indiqué !

Exemple d'appel du SWF

<div id="emplacement_carrousel" style="text-align:center;"></div>
	<script type="text/javascript">
	lancerFlash('emplacement_carrousel', '<object id="flashcontent" type="application/x-shockwave-flash" 
        data="swf/carrousel.swf" width="600" height="110">\
	 <param name="movie" value="swf/carrousel.swf" />\
	 <param name="quality" value="best" />\
	 <param name="scale" value="noscale" />\
	 <param name="bgcolor" value="#FFFFFF" />\
	 <param name="align" value="TL" />\
	 <param name="allowScriptAccess" value="always" />\
	 <param name="menu" VALUE=false />\
	 <param name="FlashVars" 
value="urlServeur=http://127.0.0.1/fete_foraine/&cheminImages=/images/carrousel/&listeFichiersAchargerStr=fond.jpg#chambouletout.png|Chamboule Tout|jeu_chambouletout.php#tireficelles.png|Tire ficelles|jeu_tireficelles.php" /></object>
 </script>

Mot de la fin

J'aurais pu gérer une exception en cas de tentative de chargement d'une image non trouvée... j'aurais pu faire plein de choses ! Mais cette classe dans cet état me convient pour le moment :-)

Quoiqu'il en soit, si vous apportez des améliorations, je serais ravi d'en connaitre la teneur :)

Menu horizontal en ActionScript 3

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 !

Echanges AMFPHP grâce à une classe AS3

Lors de divers projets, j'ai souhaité faire des échanges avec un serveur PHP... des appels ponctuels principalement, pour récupérer des informations de temps à autre, ou en mettre à jour et ce de manière optimisée.

Voici donc un classe personnalisées que j'ai faite :

La classe :

package outils
{
	import flash.net.NetConnection;
	import flash.net.Responder;
	import flash.events.Event;
	
	import flash.events.NetStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.AsyncErrorEvent;
	
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	
	public class Echange implements IEventDispatcher
	{
		private var diffuseur:EventDispatcher;// Permet la diffusion de l'evt complete
		
		// création de la connexion
		private var connexion:NetConnection;
		// création d'un de gestionnaire de retour des appels
		private var retourServeur:Responder;
		
		private var contenuRetour:Array;
		private var contenuRetourResultat:Boolean = false;
		private var contenuRetourRestart:String = "";
		
		/**
		* Constructeur créant la connexion vers le serveur AMFPHP
		*/
		public function Echange(urlServeur:String):void 
		{
			diffuseur = new EventDispatcher();
			
			connexion = new NetConnection();
			// connexion à la passerelle AMFPHP
			connexion.connect (urlServeur + "/amfphp/gateway.php");
			
			// écoute des différents événements
			connexion.addEventListener(NetStatusEvent.NET_STATUS, erreurConnexion);
			connexion.addEventListener(IOErrorEvent.IO_ERROR, erreurConnexion);
			connexion.addEventListener(SecurityErrorEvent.SECURITY_ERROR, erreurConnexion);
			connexion.addEventListener(AsyncErrorEvent.ASYNC_ERROR, erreurConnexion);
			
			retourServeur = new Responder (succes, echec);
		}
		
		/**
		* Méthode permettant d'appeler une méthode PHP, au max, la méthode php pourra n'avoir qu'un argument entier
		*/
		public function callFonction(nomFonction:String, ...parametres)
		{
			// appel de la méthode distante
			//connexion.call("Echange.premierAppel", retourServeur, 5);
			if(parametres.length == 0)
				connexion.call(nomFonction, retourServeur);
			else
				connexion.call(nomFonction, retourServeur, parametres0);
		}

		public function erreurConnexion(pEvt:Event):void
		{
			dispatchEvent(pEvt);
		}

		// création des fonctions de gestion de retour serveur
		private function succes(pRetour:*):void
		{
			contenuRetour = new Array();

			if(pRetour is Boolean)
			{
				contenuRetour = null;
				contenuRetourResultat = pRetour;
			}
			else if(pRetour is Array)
			{
				contenuRetour = pRetour;
			}
			else if(pRetour is String)
			{
				contenuRetour = null;
				contenuRetourRestart = pRetour;
			}

			dispatchEvent(new Event(Event.COMPLETE));
		}
		
		private function echec(pErreur:*):void
		{
			trace("echec de l'appel");
		}
		
		public function getContenuRetour():*
		{
			if(contenuRetour != null)
				return contenuRetour;
			else if(contenuRetourRestart != "")
				return contenuRetourRestart;
			else
				return contenuRetourResultat;
		}
		
		/** Méthodes à réécrire, suite à l'implémentation de IEventDispatcher */
		public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, 
										 priority:int=0, useWeakReference:Boolean=false ):void 
		{
			diffuseur.addEventListener( type, listener, useCapture, priority, useWeakReference );
		}
		public function dispatchEvent( event:Event ):Boolean 
		{
			return diffuseur.dispatchEvent(event);
		}
		public function hasEventListener( type:String ):Boolean 
		{
			return diffuseur.hasEventListener(type);
		}
		public function removeEventListener( type:String, listener:Function, useCapture:Boolean=false ):void 
		{
			diffuseur.removeEventListener( type, listener, useCapture );
		}
		public function willTrigger( type:String ):Boolean 
		{
			return diffuseur.willTrigger(type);
		}
	}
}

L'utilisation par l'exemple :

// - On met le serveur AMF dans http://127.0.0.1/amfphp/ (gateway.php doit être accessible à cet endroit en fait)
package
{
	import flash.display.Sprite;
	import outils.Echange;

	class Blabla extends Sprite
	{
		private var echanges:Echange; // Canal de connexion avec le serveur.
		
		public function appelerMethodeServeurAvecUnSeulParametre()
		{
			echanges.callFonction("Echange.envoyerPositionChoisie", "coucou le param string !");
			echanges.addEventListener(Event.COMPLETE, verifierRetourChoixPosition);
		}
		
		public function verifierRetourChoixPosition(pEvt:Event)
		{
			echanges.removeEventListener(Event.COMPLETE, verifierRetourChoixPosition);
			var contenuRetour:* = echanges.getContenuRetour();
			if(contenuRetour == true)
			{
				trace("coucou j'ai eu un retour de type Boolean avec pour valeur TRUE");
			}
		}
		
		public function AppelerMethodeServeur()
		{
			echanges = new Echange("http://127.0.0.1");
			echanges.callFonction("Echange.getListePositionsDejaChoisies"); 
			// Echange est la classe service PHP
			// getListePositionsDejaChoisies est la méthode à appeler
			
			echanges.addEventListener(Event.COMPLETE, continuerTraitement);
			echanges.addEventListener(NetStatusEvent.NET_STATUS, erreurEchange);
			echanges.addEventListener(IOErrorEvent.IO_ERROR, erreurEchange);
			echanges.addEventListener(SecurityErrorEvent.SECURITY_ERROR, erreurEchange);
			echanges.addEventListener(AsyncErrorEvent.ASYNC_ERROR, erreurEchange);
		}
		
		public function erreurEchange(pEvt:Event):void
		{
			trace("Erreur d'échange : " + pEvt);
		}
		
		public function continuerTraitement(pEvt:Event):void
		{
			var contenuRetour:* = echanges.getContenuRetour();
			
			echanges.removeEventListener(Event.COMPLETE, continuerTraitement);
			echanges.removeEventListener(NetStatusEvent.NET_STATUS, erreurEchange);
			echanges.removeEventListener(IOErrorEvent.IO_ERROR, erreurEchange);
			echanges.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, erreurEchange);
			echanges.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, erreurEchange);
		}
	}
}

Je vous l'accorde, cette classe est très limitée quand à son utilisation, mais elle me convient comme cela... un jour peut être que je la rendrais meilleure (passage de plusieurs arguments à la méthode appellée côté PHP par exemple) mais là, ca ira ^^

Utilisation d'un fichier XML

Voici un classe que j'ai faite suite à un besoin d'utiliser du XML dans mes projets... me suis dit que c'était tout de même nettement plus intéressant de passer par ma petite classe que de devoir tout gérer systématiquement dans chacun de mes projets (avec obligation de rechercher à chaque fois le fonctionnement etc etc).

La classe :

package outils
{
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLLoaderDataFormat;
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;

	public class XMLPerso implements IEventDispatcher {
		private var diffuseur:EventDispatcher;// Permet la diffusion de l'evt complete

		private var cheminXML:String;
		private var nomFichierXML:String;
		private var contenu:XML;

		private var chargeur:URLLoader;

		private var adresse:URLRequest;

		public function XMLPerso(cheminXML:String, nomFichierXML:String):void 
		{
			diffuseur = new EventDispatcher();

			this.cheminXML = cheminXML;
			this.nomFichierXML = nomFichierXML;

			adresse = new URLRequest(cheminXML+nomFichierXML);

			chargeur = new URLLoader();
			chargeur.dataFormat = URLLoaderDataFormat.TEXT;
			chargeur.load(adresse);

			chargeur.addEventListener(Event.COMPLETE, finDuChargement);
			chargeur.addEventListener(ProgressEvent.PROGRESS, avancement);
			chargeur.addEventListener(IOErrorEvent.IO_ERROR, indiquerErreur);
		}

		// définition de la fonction exécutée par l'évenement COMPLETE :
		// ( déclenchée lorsque le chargement se termine )
		public function finDuChargement(pEvt:Event):void 
		{
			contenu = new XML(pEvt.target.data);

			dispatchEvent(new Event(Event.COMPLETE));
		}
		// définition de la fonction éxecutée par l'évenement PROGRESS :
		// déclenchée à chaque avancement du chargement )
		public function avancement(pEvt:ProgressEvent):void 
		{
			//trace("in : " + pEvt.target.bytesLoaded + " chargés sur " + pEvt.target.bytesTotal);
		}
		// fonction indiquant si une erreur de chargement survient :
		public function indiquerErreur(pEvt:Event):void 
		{
			dispatchEvent(new Event(IOErrorEvent.IO_ERROR));
		}

		public function getContenu():XML {
			return contenu;
		}
		/** Méthodes à réécrire, suite à l'implémentation de IEventDispatcher */
		public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, 
		 priority:int=0, useWeakReference:Boolean=false ):void 
		{
			diffuseur.addEventListener( type, listener, useCapture, priority, useWeakReference );
		}
		public function dispatchEvent( event:Event ):Boolean 
		{
			return diffuseur.dispatchEvent(event);
		}
		public function hasEventListener( type:String ):Boolean 
		{
			return diffuseur.hasEventListener(type);
		}
		public function removeEventListener( type:String, listener:Function, useCapture:Boolean=false ):void 
		{
			diffuseur.removeEventListener( type, listener, useCapture );
		}
		public function willTrigger( type:String ):Boolean 
		{
			return diffuseur.willTrigger(type);
		}
	}
}

L'utilisation :

- On importe la classe (normal ^^)

- On créé un attribut private var xmlMessages:XMLPerso;

- On instancie l'objet pour ouvrir le fichier XML et ainsi en récupérer le contenu

xmlMessages = new XMLPerso(CHEMIN_FICHIER_XML, nomFichier);
xmlMessages.addEventListener(Event.COMPLETE, xml_messages_chargees);
xmlMessages.addEventListener(IOErrorEvent.IO_ERROR, erreurXML);

- Et on gère les événements voulus :

public function xml_messages_chargees(pEvt:Event):void
{
	var XMLDesMessages:XML = new XML(xmlMessages.getContenu());
	
	// On peut libérer les écouteurs
	xmlMessages.removeEventListener(Event.COMPLETE, xml_messages_chargees);
	xmlMessages.removeEventListener(IOErrorEvent.IO_ERROR, erreurXML);
	xmlMessages = null;
			
	for each(var msg:XML in XMLDesMessages..texte) 
	{
		trace(int(msg.@id) + " -> " + msg.@contenu);
	}
}
		
public function erreurXML(pEvt:Event):void
{
	trace("Erreur de chargement xml");
}

Le fichier XML utilisé pour cette exemple d'utilisation :

<?xml version="1.0"?>
<liste_messages>
	<texte id="1" contenu="Etes-vous sur de vouloir supprimer cette ligne ?" />
	<texte id="2" contenu="La mise à jour a échoué." />
	<texte id="3" contenu="Erreur de communication" />
</liste_messages>

Tri d'un élément de classe C#

Après m'être pris pas mal la tête pour savoir comment faire... j'ai enfin trouvé...

Contexte :

Je récupérais de 2 tables différentes des données, que je mettais dans 4 listes différentes... Ensuite, j'utilisais ces listes pour faire divers calcul, et en faire une preview avant impression... un système d'édition de recettes/dépenses en fait.
Vint la question de savoir comment trier tout ca par date...
J'avais donc : une date, un libellé, un crédit et un débit (en fonction l'un des 2 n'était pas alimenté).
Mais comment trier par date, vu que les infos venaient de 2 tables, et qu'aucune jointure n'était possible dessus ?

Tentatives infructueuses :

  1. une liste pour chaque élément : marche pas...
  2. J'ai tenté de passé par une Hashtable, avec pour clé ma date, et pour contenu, une instance de classe Ligne (la ligne étant les 4 éléments sus-cités)... mais impossible de trouver comment trier ensuite...

J'ai réussi !

Il suffisait de :

  • Passer par une Arraylist, alimentée par toutes les lignes issues de ma BDD (--> à chaque ligne de BDD : list.Add(new Ligne(date, libelle, credit, debit));)
  • Créer une classe interne à la classe Ligne :
public class LigneComparer : IComparer
        {
            public int Compare(object x, object y)
            {
                Ligne ligneA = (Ligne)x;
                Ligne ligneB = (Ligne)y;

                // On transforme les dates au format comparable : SSAA-MM-JJ HH:mm:ss
                string old_date_A = ligneA.date_ligne;
                string jour_A = old_date_A.Substring(0, 2);
                string mois_A = old_date_A.Substring(3, 2);
                string annee_A = old_date_A.Substring(6, 4);
                string horaire_A = old_date_A.Substring(11, 8);
                string new_date_A = annee_A + "-" + mois_A + "-" + jour_A + " " + horaire_A;

                string old_date_B = ligneB.date_ligne;
                string jour_B = old_date_B.Substring(0, 2);
                string mois_B = old_date_B.Substring(3, 2);
                string annee_B = old_date_B.Substring(6, 4);
                string horaire_B = old_date_B.Substring(11, 8);
                string new_date_B = annee_B + "-" + mois_B + "-" + jour_B + " " + horaire_B;

                return new_date_A.CompareTo(new_date_B);
            }
        }


Qui fait ?
Elle implémente IComparer, pour pouvoir écrire Compare(x, y) et elle transforme les dates au format MySQL (SSAA-MM-JJ HH:ii:ss... car je ne comprends pas pourquoi, mais le passage du contenu de ma table, au C#, fait automatiquement la transformation SSAA-MM-JJ HH:ii:ss de ma BDD vers JJ/MM/SSAA HH:ii:ss....), et fait une comparaison simple avec CompareTo :)

Et dans mon code, après avoir alimenté mon Arraylist, fais péter un coup de sort : list.Sort(new Ligne.LigneComparer());

Et boum !! C'est trié :)

Note : Il suffira de modifier return new_date_A.CompareTo(new_date_B); par return new_date_B.CompareTo(new_date_A); dans la classe interne pour avoir un tri décroissant ;)

Classe de connexion MySQL personnalisées pour C#

L'utilisation de cette classe nécessite l'installation préalable du MySQLConnector, dispo sur le site de MySQL, dans vos références de projet. J'ai indiqué dans les commentaires des méthodes comment les utiliser...

Installation de MySQL Connector

- Téléchargez-le sur le site de MySQL
- Dézippez puis lancez votre environnement de travail (Visual Studio par exemple)
- Créez un nouveau projet
- Ajouter la référence à Mysql.Data
- Dans toutes les nouvelles classes que vous créerez, et dans lesquelles vous aurez un accès MySQL à faire, mettez using MySql.Data.MySqlClient;

La classe :

using System;
using System.Collections.Generic;
using System.Text;
using MySql.Data.MySqlClient;

namespace VotreNameSpace
{
    public class MySQL_Perso
    {
        private static bool connected = false;
        private static string lastEx = "";
        private static MySqlCommand com;
        private static MySqlDataReader dr;
        private static MySqlConnection ConnectionRessource;
        
        /*
         * SQL.mysql_connect()
         * */
        public bool mysql_connect()
        {
            try
            {
                ConnectionRessource = new MySqlConnection("Server=votre_serveur_comme_localhost;Database=nom_de_votre_bdd;User ID=votre_login_d_acces;Password=votre_mdp_d_acces;");
                ConnectionRessource.Open();
                connected = true;
                return true;
            }
            catch (Exception Ex)
            {
                lastEx = Ex.Message;
                connected = false;
                return false;
            }
        }

        /*
         * SQL.mysql_close()
         * */
        public bool mysql_close()
        {
            if (connected)
            {
                try
                {
                    ConnectionRessource.Close();
                    connected = false;
                    return true;
                }
                catch (Exception Ex)
                {
                    lastEx = Ex.Message;
                    return false;
                }
            }
            else
            {
                lastEx = "Aucune connexion n'a encore été ouverte.";
                return false;
            }
        }

        /*
         *  MySQL_Perso SQL = new MySQL_Perso();
            SQL.mysql_connect();

            string myExecuteQuery = "SELECT MAX(codeclient) FROM `client`";

            MySqlDataReader dr = SQL.mysql_select(myExecuteQuery);

            dr.Read();
            int numClient = dr.GetUInt16(0);
            numClient += 1;
            this.numeroClientTb.Text = numClient.ToString();

            SQL.mysql_close();
         * */
        public MySqlDataReader mysql_select(string query)
        {
            try
            {
                com = new MySqlCommand(query, ConnectionRessource);
                dr = com.ExecuteReader();

                return dr;
            }
            catch (Exception Ex)
            {
                lastEx = Ex.Message;
                return dr;
            }
        }

        /*
         *  MySQL_Perso SQL = new MySQL_Perso();
            SQL.mysql_connect();

            string myExecuteQuery = "INSERT INTO `client` "
                      + "(codeclient, nomclient, prenomclient, rueclient, "
                      + "cpclient, villeclient, telclient, "
                      + "faxclient, mailclient, remarques, "
                      + "societe, banque, comptebancaire, date_insertion) VALUES "
                      + "('', '" + nom + "', '" + prenom + "', '" + adresse + "', "
                      + "'" + codePostal + "', '" + ville + "', '" + telephone + "', "
                      + "'" + fax + "', '" + email + "', '" + remarques + "', "
                      + "'" + societe + "', '" + banque + "', '" + compteBancaire + "', NOW())";

            bool retour = SQL.mysql_CMS(myExecuteQuery);

            if (retour == true) // INSERT OK
                MessageBox.Show("Le client a bien été enregistré.");
            else
            {
                MessageBox.Show("Un problème est survenu, le client n'a pas pu être enregistré.");
                MessageBox.Show(myExecuteQuery);
            }
            SQL.mysql_close();
         * */
        public bool mysql_CMS(string query)
        {
            try
            {
                com = new MySqlCommand(query, ConnectionRessource);

                com.ExecuteNonQuery();

                return true;
            }
            catch (Exception Ex)
            {
                lastEx = Ex.Message;
                return false;
            }
        }

        public string mysql_error()
        {
            if (connected)
            {
                if (lastEx != "")
                {
                    return lastEx;
                }
                else
                {
                    return "Il n'y a encore y aucune erreur";
                }
            }
            else
            {
                return "Erreur : Aucune connection SQL n'a encore été établie";
            }
        }
        /*
        *  string numeroFacture = SQL.SafeSqlLiteral(this.numeroFactureTb.Text);
        * */
        public string SafeSqlLiteral(string inputSQL)
        {
            inputSQL = inputSQL.Replace("", "[[");
            inputSQL = inputSQL.Replace("%", "%");
            inputSQL = inputSQL.Replace("_", "_");
            inputSQL = inputSQL.Replace("'", "''");
            return inputSQL;
        }
    }
}

Infos : Ne cherchez pas, il est impossible d'accéder à un serveur genre free, ou autre à partir d'une de vos applis :) j'ai déjà tenté ^^

Jauge visuelle à partir d'un pourcentage

Classe PHP5 :

class Jauge {
	private $sUrlImgGauche;
    private $sUrlImgMilieuPlein;
    private $sUrlImgMilieuVide;
    private $sUrlImgDroite;
    
    private $iLargeurGlobaleJauge;
    private $iHauteurJauge;
    
    public $iPourcentage;
    public $sUrlDestinationClic;
    public $sAltImage;
    
    public function __construct($iPourcentage, $sAltImage, $sUrlDestinationClic = "")
    {
    	$this->setUrlImgGauche("images/jauge-gauche.gif");
    	$this->setUrlImgMilieuPlein("images/jauge-milieu-plein.gif");
    	$this->setUrlImgMilieuVide("images/jauge-milieu-vide.gif");
    	$this->setUrlImgDroite("images/jauge-droite.gif");
    	
    	$this->setLargeurGlobaleJauge(300); // 100 px
    	$this->setHauteurJauge(12); // 30 px
    	
    	$this->iPourcentage = $iPourcentage;
    	$this->sUrlDestinationClic = $sUrlDestinationClic;
    	$this->sAltImage = $sAltImage;
    }
    
    public function afficherJauge()
    {
    	$sJauge = '<div style="float:left; width:100%;">';
   
   		if($this->sUrlDestinationClic != "")
   		{
   			$sJauge .= '<a href="'.$this->sUrlDestinationClic.'" style="text-decoration:none;">';
   		}
    	$sJauge .= '<img src="'.$this->sUrlImgGauche.'" alt="'.$this->sAltImage.'" title="'.$this->sAltImage.'" border="0" height="'.$this->iHauteurJauge.'" width="4" />';
    	
    	// Partie pleine
    	$iPleine = intval($this->iLargeurGlobaleJauge * $this->iPourcentage / 100);
    	// Partie vide
    	$iVide = intval($this->iLargeurGlobaleJauge - $iPleine);
    	
    	if($this->iPourcentage > 0)
    		$sJauge .= '<img src="'.$this->sUrlImgMilieuPlein.'" alt="'.$this->sAltImage.'" title="'.$this->sAltImage.'" border="0" height="'.$this->iHauteurJauge.'" width="'.$iPleine.'" />';
    	
    	if($this->iPourcentage <= $this->iLargeurGlobaleJauge)
    		$sJauge .= '<img src="'.$this->sUrlImgMilieuVide.'" alt="'.$this->sAltImage.'" title="'.$this->sAltImage.'" border="0" height="'.$this->iHauteurJauge.'" width="'.$iVide.'" />';
    	
    	$sJauge .= '<img src="'.$this->sUrlImgDroite.'" alt="'.$this->sAltImage.'" title="'.$this->sAltImage.'" border="0" height="'.$this->iHauteurJauge.'" width="4" />';
    	
    	$sJauge .= '&nbsp;'.$this->iPourcentage.' %<br />'.$this->sAltImage;
   
    	if($this->sUrlDestinationClic != "")
   		{
   			$sJauge .= '</a>';
   		}
    	
    	$sJauge .= '</div>';
    	
    	return $sJauge;
    }
    
    public function setUrlImgGauche($sUrlImgGauche)
    {
    	$this->sUrlImgGauche = $sUrlImgGauche;
    }
    
    public function setUrlImgMilieuPlein($sUrlImgMilieuPlein)
    {
    	$this->sUrlImgMilieuPlein = $sUrlImgMilieuPlein;
    }
    
    public function setUrlImgMilieuVide($sUrlImgMilieuVide)
    {
    	$this->sUrlImgMilieuVide = $sUrlImgMilieuVide;
    }
        
    public function setUrlImgDroite($sUrlImgDroite)
    {
    	$this->sUrlImgDroite = $sUrlImgDroite;
    }
    
    public function setLargeurGlobaleJauge($iLargeurGlobaleJauge)
    {
    	$this->iLargeurGlobaleJauge = $iLargeurGlobaleJauge;
    }
    
    public function setHauteurJauge($iHauteurJauge)
    {
    	$this->iHauteurJauge = $iHauteurJauge;
    }
}

Utilisation :

$iNbMessagesPrives = 5;
$iNbMessagesMaxiAutorises = 30;
$jauge = new Jauge(ceil($iNbMessagesPrives  * 100 / $iNbMessagesMaxiAutorises ), "Quota de messages privés que vous avez reçu...", "");
echo $jauge->afficherJauge();))

Résultat possible :

Nombre de jours entre 2 dates

Comment trouver le nombre de jours entre 2 dates ?

function ecartJoursEntreDeuxDates($dDateReference, $dDateEcart)
{
	return round / (60 * 60 * 24));; 
}

Cette fonction retourne le nombre de jours d'écart ; s'il est négatif : la dateReference était plus ancienne que l'autre...

Note : Les dates sont nécessairement au format Y-m-d...

Validation syntaxique d'email

Cette fonction permet de valider une adresse email via un simple ereg. Globalement, c'est assez sympa pour au moins savoir que syntaxiquement l'email est correct... mais ca n'empêche en rien les bla@bla.com ^^

Pour une vérification ultime, rien ne vaut l'envoi de mail avec lien de validation :-)

function valider_email($s_email)
{
	return ereg("^(a-z0-9+((\.|_|\-)+a-z0-9*)*)@(a-z0-9+((\.|_|\-)a-z0-9+)*)\.(a-z{2,4})$", strtolower($s_email), $a_ereg);
}

Premier billet

Bonjour à tous :)

J'ai envie de lancer un nouveau blog, pour voir... mais surtout parce que j'aurais bien aimé que d'autres le fasse avant moi. Le thème sera donc très technique puisque ce seront des éléments de code, dans divers langages.

Ce blog recueillera donc des utilisations d'outils (contrôles C# par exemple), des algorithmes de fonctions bien pratiques (PHP ou autre), voire même des classes entières, prêtes à être utilisées par d'autres.

Have fun et commentez !