Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

Créer un diaporama pas à pas - 7 - Préchargements des images - 2 - if ... else ...

Compatible ActionScript 2. Cliquer pour en savoir plus sur les compatibilités.Par lilive (Olivier Tarasse), le 25 août 2008

Objectif

Cette série de tutoriaux, à l'usage des débutants en ActionScript 2, présente des notions fondamentales de programmation par le biais de la réalisation d'un diaporama en ligne.

Si vous n'êtes pas intéressés par la création d'un diaporama, mais que vous lisez cet article pour apprendre l'usage de l'instruction conditionnelle if … else … , vous pouvez allez lire directement ce paragraphe.

Quant au diaporama, nous avons dans l'article précédent appris à précharger toutes les images. Nous devons maintenant intégrer ce préchargement et l'usage des boutons, des barres de progression et du fondu enchaîné entre les images tels que les avions à la fin de la sixième partie.

A la fin de cet article nous aurons le résultat suivant:

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


Comment suivre cet article

Lors de l'article précédent nous avons créé une copie du diaporama que nous avions obtenu à la sixième partie. Travaillant sur cette copie, nous en avons effacé tout le code, puis écrit le programme de création des MovieClips et de préchargement suivant:

// *********  MovieClips pour les images *******************
var nbrImages:Number = 4;
var imagesMC:Array = new Array();
for (var iImage:Number = 0; iImage < nbrImages; iImage++) {
	imagesMC[iImage] = this.createEmptyMovieClip("image" + iImage, this.getNextHighestDepth());
}
 
// **********  Chargement des images  **************************
var loadingImage:Number = 0;
var mcl:MovieClipLoader = new MovieClipLoader();
mcl.loadClip("images/image0.jpg", imagesMC[0]);
 
function chargerImageSuivante() {
	loadingImage++;
	if (loadingImage >= nbrImages) return; 
	mcl.loadClip("images/image" + loadingImage + ".jpg", imagesMC[loadingImage]);
}
var mclListener:Object = new Object();
mclListener.onLoadInit = function (mc:MovieClip) {
	mc._width = 400;
	mc._height = 300;
	mc.isLoaded = true;
	mc._visible = false;
	chargerImageSuivante();
}
mcl.addListener(mclListener);

Si on exécute ce programme, le préchargement se fait, mais rien ne s'affiche et les boutons placés sur la scène ne répondent pas. Nous allons continuer à travailler sur ce même document, en y ajoutant, en les modifiant, les parties de code qui s'occupent des boutons, des fondus et des barres de progression.


I - Afficher les images ou leurs barres de progression

Nous allons laisser à l'utilisateur la possibilité de feuilleter tout l'album dès le lancement du diaporama. Si l'image qu'il désire voir est déjà chargée, il la verra, sinon il verra une barre de progression qui indique où en est le chargement de cette image.

Il sera pratique d'écrire un fonction afficherImageActuelle qu'il suffira d'appeler pour demander à afficher l'image correspondante à la valeur de la variable imageActuelle. Nous laisserons à cette fonction la charge de décider s'il faut afficher l'image ou afficher la barre de progression si l'image n'est pas encore chargée.

De la sorte, il suffira au lancement du diaporama de donner la valeur 0 à la variable imageActuelle, et d'appeler afficherImageActuelle.

Les boutons, eux, se chargeront de modifier la valeur d'imageActuelle et d'appeler afficherImageActuelle pour rafraîchir l'affichage.

Nous allons rédiger cette fonction, en commençant ce petit préalable:

1- L'instruction conditionnelle if ... else ...

Nous avons déjà vu ici l'utilisation de l'instruction conditionnelle if. Mais nous n'avons pas encore vu qu'il est possible de rajouter un else (sinon en français):

if (condition) instruction1 else instruction2

Traduisible en français par: Si la condition est vraie alors exécuter l'instruction 1 sinon exécuter l'instruction 2.

if … else … est donc à utiliser quand on veut que le programme choisisse deux comportements différents selon les cas de figure.

condition est une expression booléenne qui renvoie le résultat true ou false.

instruction1 et instruction2 peuvent être des instructions isolées ou des blocs d'instructions enclos entre accolades:

if (condition) {
	une instruction
	une autre instruction
	une autre instruction
} else {
	une instruction
	une autre instruction
}

Notons également que s'il est impossible à flash d'évaluer correctement la condition, et que son résultat est undefined, c'est l'instruction else qui sera exécutée.

Pour en savoir plus sur if … else … voyez notamment cet article.

Le préalable est terminé, revenons à la fonction afficherImageActuelle :

2- La fonction afficherImageActuelle

Ajoutons à notre code une nouvelle fonction 1):

function afficherImageActuelle() {
	progressMC._visible = false;
	if (imagesMC[imageActuelle].isLoaded) startFondu(imagesMC[imageActuelle]);
	else afficherProgressBar();
}

Cette fonction commence par rendre invisible une éventuelle barre de progression qui aurait été affichée jusque-là.

Puis la fonction doit se comporter différemment, selon que l'image que l'on veut afficher est chargée ou pas: si l'image est chargée alors elle doit lancer le fondu qui la fait apparaître, sinon elle doit faire apparaître la barre de progression.

Nous allons devoir utiliser if … else … pour tester si l'image est chargée et appeler selon les cas la fonction startFondu (lancer le fondu) ou la fonction afficherProgressBar. Nous écrirons plus loin ces deux fonctions.

Quelle condition allons-nous écrire après le if ? C'est justement là qu'intervient la nouvelle propriété isLoaded que nous avons introduit lors du dernier article.

if (imagesMC[imageActuelle].isLoaded) startFondu(imagesMC[imageActuelle]);
else afficherProgressBar();
  • Si imagesMC[imageActuelle] est chargée, sa propriété isLoaded vaut true, et la condition est donc vraie, le fondu est lancé.
  • Si imagesMC[imageActuelle] n'est pas chargée, sa propriété isLoaded n'existe pas, l'évaluation de imagesMC[imageActuelle].isLoaded retourne donc la valeur undefined. Comme nous l'avons vu au 1) c'est le else qui sera exécuté, et la barre de progression affichée.

N'oublions pas de demander à la fin du code l'affichage de la première image au lancement du diaporama 2) :

var imageActuelle:Number = 0;
afficherImageActuelle();


II - Remettre en marche les boutons

Nous pouvons maintenant redonner tranquillement leur rôle aux boutons, en ajoutant et modifiant légèrement les fonctions qui s'en chargeaient jusque-là 3) . Notez que nous renommons ces fonctions qui s'appelaient avant chargerImageSuivante et chargerImagePrecedente :

function afficherImageSuivante() {
	imageActuelle++ ;
	if (imageActuelle >= nbrImages) imageActuelle = 0;
	afficherImageActuelle();
}
function afficherImagePrecedente() {
	imageActuelle-- ;
	if (imageActuelle == -1) imageActuelle = nbrImages - 1;
	afficherImageActuelle();
}
var nextBtn:MovieClip = this["nextBtn"];
nextBtn.onPress = afficherImageSuivante;
 
var lastBtn:MovieClip = this["lastBtn"];
lastBtn.onPress = afficherImagePrecedente;

Rien de bien sorcier: les boutons modifient la valeur d'imageActuelle, index de l'image que désire voir l'utilisateur, et appellent afficherImageActuelle qui affiche cette image ou la barre de progression.


III - Les barres de progression

Quand la barre de progression est affichée, elle doit refléter l'avancement du chargement de l'image qu'a demandé à voir l'utilisateur, dont le numéro est imageActuelle.

1- Vider la barre de progression

Chaque exécution de afficherImageActuelle pour une image non chargée appelle la fonction afficherProgressBar. Rajoutons au programme la fonction qui s'appelait initProgressBar, en la renommant en afficherProgressBar, et ajoutons-lui une ligne:

var progressMC:MovieClip = this.createEmptyMovieClip("progress",this.getNextHighestDepth());
progressMC._visible = false;
var progressTF:TextField = progressMC.createTextField("text", 0, 100, 120, 200, 20);
progressTF.textColor = 0xffffff;
progressTF.autoSize = "left";
 
function afficherProgressBar() {
	progressMC.clear();
	drawFilledRectangle(progressMC, 0, 0, 400, 300, 0, 50);
	drawRectangle(progressMC, 100, 140, 200, 15, 2, 0xffffff, 100);
	// Afficher le numéro de l'image en cours de chargement:
	progressTF.text = "Chargement de l'image " + (imageActuelle + 1) + " ...";
	progressMC._visible = true;
}

Ainsi, chaque clic sur un bouton qui amène à une image non chargée déclenchera l'affichage d'une barre de progression vide, pour l'instant.

Remarquez aussi le petit changement qui consiste à afficher le numéro de l'image dans le message de progression du chargement, pour nous permettre de mieux suivre les opérations.

N'oublions pas de rajouter les fonctions de dessin drawRectangle et drawFilledRectangle qui elles ne changent pas 4) .

2- Remplir la barre de progression

La barre de progression s'affiche donc dans le cas où l'utilisateur demande à voir une image qui n'est pas encore complètement chargée.

La méthode onLoadProgress est appelée régulièrement lors du chargement d'une image. Il y a deux cas de figure:

  • Soit l'image en train de se charger et celle que l'utilisateur demande à voir, et il faut donc remplir la barre de progression pour rendre compte de l'avancement du chargement.
  • Soit l'image en train de se charger n'est pas celle que demande à voir l'utilisateur, et celle-ci n'a pas encore commencé à se charger. La barre de progression doit alors rester vide.

Il faut donc modifier la fonction onLoadProgress pour qu'elle ne remplisse la barre que si le MovieClip en cours de chargement est celui qui correspond à la valeur d'imageActuelle:

mclListener.onLoadProgress = function(mc:MovieClip, bytesLoaded:Number, bytesTotal:Number) {
	if (!progressMC._visible) return;
	if (mc != imagesMC[imageActuelle]) return;
	var width:Number = (bytesLoaded / bytesTotal) * 200;
	drawFilledRectangle(progressMC, 100, 140, width, 15, 0xffffff, 100);
}

Pour arriver au résultat désiré, nous rajoutons la ligne:

if (mc != imagesMC[imageActuelle]) return;

!= est l'opérateur “différent de”. Si la fonction onLoadProgress a été appelée pour un MovieClip autre que le MovieClip correspondant à la valeur de imageActuelle, cette ligne met fin à la fonction, et la barre de progression n'est pas remplie.

3- Afficher une image à la fin de son chargement

Il ne faut pas oublier d'afficher l'image à la fin de son chargement:

mclListener.onLoadInit = function (mc:MovieClip) {
	mc._width = 400;
	mc._height = 300;
	mc._visible = false;
	mc.isLoaded = true;
	if (mc == imagesMC[imageActuelle]) {
		progressMC._visible = false;
		startFondu(imagesMC[imageActuelle]);
	}
	chargerImageSuivante();
}

Nous modifions donc la fonction onLoadInit pour que, si l'utilisateur était en train de voir la barre de progression de l'image qui vient de finir de se charger:

  1. La barre de progression disparaisse
  2. L'image chargée apparaisse

La condition (mc == imagesMC[imageActuelle]) teste si le MovieClip qui vient de terminer de se charger et le MovieClip que désire voir l'utilisateur sont les même, en utilisant l'opérateur d'égalité == pour comparer le MovieClip auquel fait référence la variable mc et le MovieClip auquel fait référence le imageActuelle-ième élément du tableau imagesMC.

4- Et le délai avant l'apparition de la barre de progression ?

Le délai que nous avions mis en place pour différer l'affichage de la barre de progression ne semble plus nécessaire maintenant que nous préchargeons les images. Nous n'utiliserons donc plus de variable startLoadTime.


IV - Le fondu

Il nous reste encore à écrire cette fameuse fonction startFondu, qui doit lancer l'apparition d'une image.

1- Premier jet

Nous utiliserons une nouvelle variable displayedImageMC de type MovieClip qui va nous servir à mémoriser quelle est l'image actuellement affichée. “L'image actuellement affichée” est la dernière image qui est apparue à l'affichage.

Introduisons aussi une variable incomingImageMC qui fera référence à l'image en train d'apparaître, c'est-à-dire celle dont l'opacité se modifie au fur et à mesure du fondu.

Notre fondu va légèrement changer de technique. Cette fois, nous mettrons l'image qui doit apparaître au-dessus (devant) l'image déjà affichée, avec une opacité de 0%, et nous augmenterons progressivement cette opacité.

Nous veillerons toujours à proprement finaliser la transition dans le cas où l'utilisateur clique sur un bouton alors qu'un fondu était en cours.

var isFonduEnCours:Boolean = false;	// true si un fondu est en cours
var displayedImageMC:MovieClip;	// Image déjà affichée
var incomingImageMC:MovieClip;		// Image en cours d'apparition
 
function startFondu(imageMC:MovieClip) {
	// Il faut passer un paramètre à la fonction: le MovieClip qui doit apparaître.
 
	// Finaliser le fondu précédent s'il n'est pas terminé:
	if (isFonduEnCours) finaliserTransition();
	// S'assurer que imageMC est "devant" l'image déjà affichée:
	if (displayedImageMC.getDepth() > imageMC.getDepth()) {
		displayedImageMC.swapDepths(imageMC);
	}
	// Retenir quelle image en train d'apparaître:
	incomingImageMC = imageMC;
	// Lancer le fondu:
	incomingImageMC._visible = true;
	incomingImageMC._alpha = 0;
	incomingImageMC.onEnterFrame = transition;
	// Noter qu'un fondu est en cours:
	isFonduEnCours = true;
}
 
function transition() {
	incomingImageMC._alpha += 10;
	if (incomingImageMC._alpha >= 100) finaliserTransition();
}
function finaliserTransition() {
	// Terminer le fondu même s'il n'était pas fini:
	incomingImageMC.onEnterFrame = undefined;
	incomingImageMC._alpha = 100;
	displayedImageMC._visible = false;	// Rendre invisible l'image précédente
	displayedImageMC = incomingImageMC;	// Retenir quelle est la nouvelle image affichée
	isFonduEnCours = false;		// Noter que le fondu est terminé
}

2- Premier résultat

Nous pouvons maintenant exécuter notre nouveau code, que vous trouverez intégralement en pièce jointe 5) :

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


3- Amélioration

Quand on exécute un code après tant de modifications, il n'est pas rare que cela ne marche pas, et qu'on se retrouve à nouveau en pleine phase de débogage (cf. article précédent). Ici, le programme donne a peu près le résultat attendu, mais pas tout à fait. Voyez-vous se profiler l'occasion rêvée de vous livrer à un petit exercice de débogage ;-) ?

Il y a un problème quand on affiche la première image chargée, qu'on clique pour voir l'image suivante, que la barre de progression apparaît 6), et qu'avant la fin du chargement de cette deuxième image on clique vers l'arrière pour revoir la première image. On se retrouve alors à n'avoir plus rien affiché. Vous pouvez essayer de comprendre par vous-même le pourquoi de ce phénomène.

Que se passe-t-il? La solution:
Cela vient du fait qu'après l'affichage de la première image, displayedImageMC désigne le premier MovieClip. Le clic vers l'image suivante fait apparaître la barre de progression, displayedImageMC n'est donc pas modifié. Le clic vers l'image précédente lance le fondu pour faire apparaître le premier MovieClip. La fonction startFondu est appelée pour lancer un fondu entre le premier MovieClip et le MovieClip displayedImageMC, qui est aussi le premier MovieClip. On demande au MovieClip de faire un fondu avec lui-même! D'où des conséquences inattendues.

Un bon moyen de résoudre ce problème est de demander à startFondu de vérifier qu'on ne lui demande pas de faire un fondu entre un MovieClip et lui-même:

function startFondu(imageMC:MovieClip) {
	if (isFonduEnCours) finaliserTransition();
	if (imageMC == displayedImageMC) return;
	if (displayedImageMC.getDepth() > imageMC.getDepth()) {
		displayedImageMC.swapDepths(imageMC);
	}
	incomingImageMC = imageMC;
	incomingImageMC._visible = true;
	incomingImageMC._alpha = 0;
	incomingImageMC.onEnterFrame = transition;
	isFonduEnCours = true;
}

Et voilà 7) :

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


Conclusion

Le diaporama est de nouveau opérationnel. Le préchargement fonctionne, et le programme n'attend plus que l'utilisateur demande à voir une image pour la télécharger. Nous avons bien gagné en confort d'utilisation. Il reste cependant un point noir, que vous avez peut-être remarqué: si l'utilisateur, par l'usage du bouton image précédente, demande à voir la dernière image dès le lancement du diaporama, et puisque les images se chargent les unes après les autres, il va devoir attendre le chargement complet de toutes les images de l'album avant qu'apparaisse la dernière image. Nous résoudrons ce problème dans le troisième et dernier article de la série consacrée au préchargement.

Comme d'habitude, pour faire progresser ce tutoriel, vos commentaires sont les indispensables bienvenus sur le forum. Vous pouvez répondre au message concernant ce tutoriel ou ouvrir un nouveau sujet.


Pour en savoir plus

Pour avoir des précisions ou des renseignements complémentaires, vous pouvez consulter 8):


Navigation: Sommaire page précédente page suivante Index

1) , 2) , 3) , 4) , 5) Vous pouvez télécharger les fichiers de code correspondants à cet article et les swf compilés, le tout dans une archive compressée. Si vous utilisez Flash IDE, cliquez ici. Si vous utilisez un environnement intégrant mtasc et swfmill, cliquez ici
6) , 7) Au moment où vous regardez un swf inclus dans cette page, le préchargement des images est peut-être déjà terminé. Si vous désirez voir son comportement pendant le préchargement, rechargez la page, ce qui relancera le préchargement des images.
8) Les références à l'aide de Flash concernent la documentation de Flash CS3, accessible par l'IDE de Flash CS3 ou par le site d'Adobe (Support > Documentation).