Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox

DisplayObject et Stage: Erreur 1009

par AngelStreet

Keyword : Erreur 1009, Stage, Préchargement
Public : Tout public
Prérequis : Aucun

Introduction

Le but de ce tutoriel est de fournir une explication claire sur l'apparition de l'erreur 1009:
“Il est impossible d'accéder à la propriété ou à la méthode d'une référence d'objet nul.”
Ce tutoriel fournira des conseils pratiques, illustrés de code afin de corriger une bonne fois pour toute ce problème récurrent, difficile à analyser par les débutants.

Le problème

Exemple d'introduction

Kainry à un problème quelle poste sur le forum Mediabox .

Le problème est le suivant:

J'utilise le code ci-dessous:

import Momo;
(...)
Module = new Momo();
   stage.addChild(Module);

et voici l'erreur que j'obtiens :

TypeError: Error #1009: Il est impossible d'accéder à la propriété ou à la méthode d'une référence d'objet nul.
at Momo/PlaceUnits()
at Momo()
at ModuleFinal()

Explication

“Error #1009: Il est impossible d'accéder à la propriété ou à la méthode d'une référence d'objet nul.”
Dans l'exemple précédent, le stage est nul !

En général, il existe 2 situations qui peuvent occasionner cette erreur.
1. Vous tentez d’accéder aux propriétés d'un DisplayObject avant qu'il ne soit complètement chargé.
Ce type d'erreur arrive généralement lors du chargement de l'application principale ou
lors du chargement dynamique d'un swf externe.
2. Vous tentez d'accéder au stage d'un DisplayObject (MovieClip, les Sprite, les Shape, etc) avant qu'il ne soit ajouté à la scène.

Kainly est dans le cas numéro 2.

Le code:
package  {
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class Momo extends Sprite{
		
		public var module:Array; 
		public var nbUnitX = 6;
		public var nbUnitY = 12;
		public var nbUnit;
		public var unit:Unit ;
		
		public function Momo() {
			trace ("j'suis là"); //test d'importation de classe = OK
			PlaceUnits(72);
		}
		  public function PlaceUnits( amount:int ):void{
			module = new Array(); 
			for(var i:int = 0; i < amount; i++){ //création du module à base du MovieClip Unit.
			    trace("moi aussi mais tu me vois pas");// vérification de l'importation du tableau = OK
			    unit = new Unit();
			    unit.x = (i % nbUnitX) * 18.5 + unit.width * .5 // positionnement du MC sur l'axe des X + mise à l'échelle
			    unit.y = int(i / nbUnitX) * 18.5 + unit.height * .5; // positionnemnet du MC sur l'axe des Y + mise à l'échelle
			    module.push( unit );
			    stage.addChild( module[i] );
			}
		}
	}
}
L'explication de Lilive:
“Quand tu crées un objet Momo avec new Momo() la méthode constructeur de Momo est appelée. Dans cette méthode tu fais:
PlaceUnits(72);

Hors, dans la fonction PlaceUnits tu as:
stage.addChild( module[i] );

stage est une propriété des DisplayObject (les MovieClip, les Sprite, les Shape, etc)
Si un DisplayObject est ajouté sur scène, stage est bien une référence à la scène.
Mais si le DisplayObject n'est pas sur la scène, stage vaut null.
Dans ton cas, vu que tu appelles PlaceUnits(72) avant le stage.addChild(Module), stage vaut null,
d'où le message d'erreur 1009 que tu obtiens en tentant de faire stage.addChild( module[i] )

C'est une erreur classique, qui se résout de différentes manières, par exemple en écoutant l'évènement ADDED_TO_STAGE qui est diffusé quand un DisplayObject est ajouté à la scène.

La solution

Solution 1: Effectuer un préchargement sur tous vos projets

Si vous devez utiliser des éléments chargés dynamiquement vous devez vérifier qu'ils sont entièrement chargé avant de les utiliser. Il est possible d'utiliser un écouteur EnterFrame. L'écouteur déclenche une fonction onLoading de manière répétée. La fonction onLoading détermine si le chargement est complet. Pour faire ceux, on utilise les propriétés bytesLoaded (bytes chargé) et bytesTotal (bytes total) du stage.loaderInfo. Si bytesLoaded == bytesTotal alors le chargement est fini.

package {
/**
 * Main Class of the document.
 */
[SWF(width=800, height=600, backgroundColor=0xFFFFFF, frameRate=30, scriptTimeLimit=15)]
   public class Template extends Sprite {		
	public function Template() {
		if (stage){ // Si le stage est ajouté à la scène on lance la fonction _init()
		     _init();
		} 
		else { //Sinon on ajoute un écouteur
		     addEventListener(Event.ADDED_TO_STAGE,_init, false, 0, true); 
//On attend que le swf soit ajouté à la scéne (Optionnel: compatibilité avec Flash Develop)
		}
	}
// Lorsque le swf est ajouté à la scène on ajoute un écouteur EnterFrame qui va appeler à chaque frame _onLoading()
	private function _init($e:Event = null):void {
		trace("Init...");
		removeEventListener(Event.ADDED_TO_STAGE, _init);
		addEventListener(Event.ENTER_FRAME,_onLoading,false,0,true);
	}
	// Préchargement
	private function _onLoading($e:Event = null):void {
		// On calcule le nombre de bytes chargé et s'il est égale au nombre de bytes total on lance la fonction _onLoadingComplete()
		var loaded:Number = stage.loaderInfo.bytesLoaded;
		var total:Number = stage.loaderInfo.bytesTotal;
		trace("Loading... "+ Math.floor((loaded/total)*100)+ "%");
		if (loaded == total) {
			removeEventListener(Event.ENTER_FRAME, _onLoading);
			_onLoadingComplete();
		}
	}
        // Chargement terminé
	private function _onLoadingComplete():void {
		//Commencez votre code ici
	}
Solution 2: Ajouter un écouteur AddedToStage dans vos classes héritant d'un DisplayObject

Afin d'éviter d'utiliser la propriété stage d'un objet qui n'a pas été ajouté à la scène,
il est possible d'utiliser l'écouteur AddedToStage, littéralement Ajouté à la scène. Lorsque l'object est ajouté on peut alors utilisé le stage.

package  {
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.display.Sprite;
	import flash.events.Event;
	
	public class Momo extends Sprite{
		
		public var module:Array; 
		public var nbUnitX = 6;
		public var nbUnitY = 12;
		public var nbUnit;
		public var unit:Unit ;
		
		public function Momo() {
			trace ("j'suis là"); //test d'importation de classe = OK
			addEventListener(Event.ADDED_TO_STAGE,_onAddedToStage, false, 0, true); // On ajoute l'écouteur ici
			
		}
		  public function PlaceUnits( amount:int ):void{
			module = new Array(); 
			for(var i:int = 0; i < amount; i++){ //création du module à base du MovieClip Unit.
			    trace("moi aussi mais tu me vois pas");// vérification de l'importation du tableau = OK
			    unit = new Unit();
			    unit.x = (i % nbUnitX) * 18.5 + unit.width * .5 // positionnement du MC sur l'axe des X + mise à l'échelle
			    unit.y = int(i / nbUnitX) * 18.5 + unit.height * .5; // positionnemnet du MC sur l'axe des Y + mise à l'échelle
			    module.push( unit );
			    stage.addChild( module[i] );
			}
		}
	}
}
	//Si l'objet est ajouté à la scène alors on appel PlaceUnits
	private function _onAddedToStage($e:Event):void {
		PlaceUnits(72);// PlaceUnits peut utiliser le stage qui ne sera pas nul
	}

Conclusion

J'espère que grâce à ce tutoriel l'erreur 1009 n'a plus aucun secret pour vous. En utilisant les astuces proposées vous ne devriez plus rencontrer cet erreur à l'avenir.

Liens utiles

- Kainly: Post de son problème avec la réponse de Lilive