June 2,2010 00:11

FLASH AS3.0的TypeError: Error #1009: 無法存取 Null 物件參考的屬性或方法。(stage與addToStage)

玩AS3.0到一定的程度時!

一定都會碰到這個錯誤:

TypeError: Error #1009: 無法存取 Null 物件參考的屬性或方法。


寫完幾百行的程式以後

輸出顯示出這個錯誤訊息!

我相信各位一定都會有想砸電腦的衝動吧!(這也是AS3.0麻煩的地方!)

來回檢查個幾百次!邏輯都沒問題阿!

就是找不到錯誤!!!

難道就能放任他無解嗎??

後來找到原因了!

首先我們先來看看Event.ADDED這個事件吧!!

我們都知道任何Display Object(可視物件)被new(建構)出來時

他不會顯示出來!而是存在電腦記憶體裡面

必須透過addChild()這個方法將可視物件顯示出來

而在使用addChild()加入時

這時就會發生Event.ADDED這個事件!


接下來是Event.ADDED_TO_STAGE這個事件

ADOBE寫的原文說明:
加入至舞台上顯示清單的 DisplayObject(可視物件) 實體,方式為直接加入或

透過加入包含 DisplayObject 實體的子樹狀結構(就是他的子繼承物件)來加入。

如果直接加入 DisplayObject 實體,便會在ADDED_TO_STAGE事件之前發生 ADDED 事件。




看了ADDED_TO_STAGE官方說明!相信還是有看沒有懂

意思就是說一個DisplayObject可視物件如果是用addChild()方法加入到

"場景"上,就會發生ADDED_TO_STAGE這個事件!!

那ADDED跟ADDED_TO_STAGE這兩個事件有啥不同勒?

我整理一下!

當被使用addChild加入時,會發生 ADDED事件
如果被addChild加入時, 該物件是存在stage之下, 就會同時發生 ADDED與ADDED_TO_STAGE事件(只是ADDED會先發生!)

接下來講一下stage這個類別
下面這是官方的說法!

顯示物件的「舞台」。 Flash 應用程式只有一個 Stage 物件。 例如,您可以建立多個顯示物件並將之載入顯示清單中,如此,每個顯示物件的 stage 屬性都會參照到相同的 Stage 物件 (即使顯示物件屬於載入的 SWF 檔案亦然)。

如果顯示物件未加入顯示清單,它的 stage 屬性便會設為 null。



會發生Error #1009的原因在於:

stage屬性, 是可視物件DisplayObject擁有的屬性

就像parent和root屬性一樣,都是唯讀

stage屬性一開始為 null ,一定要可視物件被加入至stage後!

stage屬性才會有值

所以在建構函式時就偵聽stage的話(因為你的可視物件還沒加到場景,上面有說ADDED會發生在ADDED_TO_STAGE之前),就會發生

"Error #1009無法取存null的屬性或方法"

所以我們只要讓stage去偵聽ADDED_TO_STAGE事件!這樣可視物件

就能被加到場景上了(這樣stage就不會是空值了!!)



這種錯誤最常發生於A.SWF去載入B.SWF時


以下我們就舉奶綠老師的範例!


package  {    
 import flash.display.MovieClip;  
 import flash.events.Event;  
   
 public class ChildMC extends MovieClip{    
    
  public function ChildMC()  {     
   trace(stage);  
   //如果該檔是直被被執行, 沒有被載入的情況 下, stage屬性會有值,  
   //如果是被載入, 一開始的stage會是null  
   //所以一開始對 stage.addEventListener事件, 就會發生錯誤。  
     
   this.addEventListener(Event.ADDED_TO_STAGE , addToStage
Handler);  

   //偵聽Event.ADDED_TO_STAGE事件,  
   //該事件指的是,當自已被加入場景上時,會觸法該事件  
   //因為被加入到場景上, 所以之後的stage屬性就不會是 null  
     
   this.addEventListener(Event.REMOVED_FROM_STAGE , removed
FromStageHandler);  

   //當該物件被從場景上移除時  
  }      
  private function addToStageHandler(e:Event):void {  
   //這兒即可自由的存檔stage屬性  
  }  
  private function removedFromStageHandler(e:Event):void {  
   //把所有的事件通通取消掉。  
   this.removeEventListener(Event.ADDED_TO_STAGE , addToStage
Handler);  

   this.removeEventListener(Event.REMOVED_FROM_STAGE , remov
edFromStageHandler);  

  }  
 }   
}



所以,以後最保險的方法就是先讓場景偵聽Event.ADDED_TO_STAGE這個事件!這樣就能保證場景不會是NULL啦!!!!


===========2012/5/2補充====================================
最近又回來看到我以前寫的這一篇!覺得會誤導人!於是在下面這邊我在另外補充
"Error #1009無法取存null的屬性或方法"

其實會發生這種錯誤除了上面我所提的場景還沒進來就去使用場景屬性問題外!還有很多可能會發生這種錯誤

隨便舉一個例子好了!

範例:
var mc:MovieClip;

trace(mc.name);

嘿!這時候也會出現"Error #1009無法取存null的屬性或方法"

基本上會出現這種錯誤就是你的物件是null(空的)

而null本身並沒有屬性(變數)或是方法(函數)

所以並有東西可以讓你存取!於是就會拋出這個錯誤!!


上面範例會出這種錯的原因

是我們只宣告mc它是MovieClip型別!但是並沒有給他值!所以mc的預設是null

這時候我們再去trace(mc.name);就會變成是null.name

而null本身就沒有name這個屬性(也可以說它沒有任何屬性),所以就會出錯!


解決方法就讓你的變數不是null

var mc:MovieClip=new MovieClip();//這樣變數mc就是存了一個MovieClip物件而不是null了

這樣就不會發生那個錯誤!


所以呢!會發生這個錯誤時!請去檢查你的物件是不是null吧!



  • sayaku 發表於樂多回應(6)引用(0)ActionScript 3.0編輯本文
    樂多分類:藝術/設計切換閱讀版型 │昨日人次:7 │累計人次:17404 │標籤:flash,actionscript 3.0,as3.0
     

    引用URL

    http://cgi.blog.roodo.com/trackback/12582833

    回應文章

    你好,看到這篇文章,很高興終於找到接近的答案了
    不過因為我不會寫package,所以我都是直接寫在flash裡面

    我遇到的問題是,當我按下按鈕後跳到最後一格,執行loader時就跳出一堆下面的東西,我按鈕有幾個就跳出幾組。
    TypeError: Error #1009: 無法存取 Null 物件參考的屬性或方法。
    at extension_fla::Timeline_14/k05()

    請問我如果要直接寫在flash裡,該怎麼寫呢?
    ---------------------------------------------
    版主回覆:
    如果是寫在FLASH裡面~基本上是不會有我上面寫的那些問題!

    會出現TypeError: Error #1009: 無法存取 Null 物件參考的屬性或方法。除了我上面說的那些問題最主要就是你想要使用某些物件的屬性或是方法時而該物件並未被建構出來!!所以會發生這種錯誤!

    而Loader最常會發生這種錯誤!我猜應該是你要load進來的物件還沒有完全load進來就去對這個物件的屬性或方法去做存取!才會發生這種錯誤!!

    可以試試對這個要load進來的物件作一個讀取完成的偵聽事件(Event.COMPLETE)再去對這個物件的屬性或方法做存取就不會有問題了!!試試看吧!!
    | 檢舉 | Posted by iris at April 22,2011 16:19

    你好!!
    可否請教你一些問題
    我目前想製作一個Flash選單頁面
    其中的一個按鈕可以load用pv3d輸出的swf檔
    就會發生
    TypeError: Error #1009: 無法存取 Null 物件參考的屬性或方法。
    ↑這個問題
    看了你的文章
    我就在主場景加了ChildMC類別檔
    結果變成出現以下問題
    1046: 找不到 Type,或它不是編譯時期常數:MouseEvent。
    我在主場景寫了載入外部swf檔的程式
    btn.addEventListener(MouseEvent.CLICK, fl_MouseClickHandler);

    function fl_MouseClickHandler(event:MouseEvent):void
    {
    var req:URLRequest = new URLRequest("Main.swf");
    var loader:Loader = new Loader();
    loader.load(req);
    addChild(loader);

    }
    其中Main.swf就是用pv3d類別輸出的swf檔

    請問我是不是哪個步驟錯了?

    感激不盡!!!
    ---------------------------------------------
    版主回覆:
    不太懂為什麼你要直接加入ChildMC這個類別??
    那只是一個範例.........

    依你這樣描述~應該是要去修改PV3D的檔!
    而不是直接加入ChildMC類別.......

    而且光你附上的程式碼我也看不出個蹊翹....

    | 檢舉 | Posted by 炸蝦 at November 16,2011 14:31

    真是抱歉問了蠢問題
    因為其實我pv3d剛開始學
    幾乎都不會

    多謝你的提醒
    我解決問題了

    謝謝!!!!
    | 檢舉 | Posted by 炸蝦 at November 16,2011 18:23

    哦哦,這篇文章幫了我大忙阿!
    最近也是在學寫AS3,光寫兩個類別就遇到這個魔王了 囧
    一個是繪製圓球的類別,直接使用時編譯通過沒問題
    另一個是呼叫圓球後跑圓形動畫,這時候魔王就出現了= =
    錯誤顯示位置是我圓球的類別有問題…但是直接使用就安穩的出現再舞台上

    照著書本打程式碼也都無誤,真的有衝動想砸電腦
    後來發現是new的那一行程式碼出包,也就是創造球的時候就已經爆了
    然後搜尋找到這篇文章…看到檔案若是被載入時stage是null
    研判應該是在球類別有使用drawing API,沒有stage相當於沒有畫布
    因此修改了圓球,當球真正被加入舞台顯示時才開始繪製。
    然後就看到動畫終於編譯成功…看著球在跑感覺像是升級了一樣XD
    話說我看得書的作者使用的是CS3,作者做夢應該也沒想到同樣的程式碼現在就爆了 囧
    | 檢舉 | Posted by 政洋 at October 5,2012 19:41

    您好~~有個問題想請教您~
    近期要做一款遊戲,我們分了很多的場景(玩家可按按鈕選擇場景),但人物到更衣場景時,需要更換衣服(類似紙娃娃那樣)當人物換完裝出場景去另一個場景時人物身上的服飾還能維持換裝完的樣子,想請問這程式碼要如何撰寫?程式碼是否可以繼承上一個場景的程式碼?
    | 檢舉 | Posted by rara at October 18,2012 18:50

    版主你好:
    我的AS3.0加入了以下程式碼就會報1009的錯誤
    主要是用來監聽音樂播放長度/音樂總長度
    可是我又不知道從哪邊更改,可以幫幫我嗎
    一個AS3的初學者

    stage.addEventListener(Event.ENTER_FRAME,function()
    {
    // time更新
    if(soundcontrol) pos_t.text = getTime(soundcontrol.position);
    else pos_t.text = getTime0);
    if(my_sound) len_t.text = getTime(my_sound.length);
    else len_t.text = getTime(0); });


    // 時間計算
    function getTime(Timer){
    var mil = Math.floor(Timer);
    var sec = Math.floor(mil / 1000);
    var min = Math.floor(sec / 60);

    if(min > 99) min = 99;
    sec %= 60;
    mil %= 1000;

    if(min < 10) min = "0" + min;
    if(sec < 10) sec = "0" + sec;

    //var z = "";
    //if(mil < 100) z += "0";
    //if(mil < 10) z += "0";
    //mil = z + mil;

    return min + ":" + sec ;//+ mil;}
    | 檢舉 | Posted by tobasi at November 19,2013 09:22