[ActionScript] 疑難雜症篇 - Error #1009無法取存null的屬性或方法

前陣子朋友問我造成「Error #1009無法取存null的屬性或方法」的原因,這個問題其實在AS 3.0很常見,主要原因為Display Object不當存取stage屬性。本文將由AS 3.0 DisplayList概念切入,說明Stage與Display Object之間的關係,接著解釋Error #1009發生緣由以及可能的解決方法


一、ActionScript 3.0 Display List概念

Display List是指被Flash runtime呈現的Display Objects階層架構,只要Display Object被加入List中,Flash runtime就會將其內容呈現在畫面上,整個Display List的root節點為Stage class的物件實體,當Flash runtime啟動時會自動建立物件並加入Display List(如下圖1),可以把它想像成舞台,所有的顯示物件都會在上面呈現


 圖1

Flash runtime在載入一個.swf檔案後,會將其主程式的物件實體自動加入List(如下圖2),即使主程式物件實體沒有要顯示任何物件也會被加入,它是Stage的唯一子節點


圖2 

主程式物件加入Display List後,就可利用Display Object Container物件的addChild(),將顯示物件(MovieClip, Text, Button)加入Display List以顯示在畫面上(如下圖3),只要是加入到Display List的顯示物件,都可以透過stage屬性取得Stage物件實體參考,如果不在Display List的物件存取stage屬性會得到null的回傳值


圖3 

二、「Error #1009無法取存null的屬性或方法」問題發生原因

造成此項問題的主因為「不在Display List的物件存取stage的屬性或是方法」,例如:某個Display Object的寬為整個舞台寬度的一半,但該物件並不在顯示清單上,所以在執行後會發生Error #1009無法取存null的屬性或方法的問題:

myDisplayObject.width = myDisplayObject.stage.stageWidth/2;

這樣的問題常常發生在載入另一個swf檔案時候發生,以下將以A.swf載入B.swf為例子說明問題發生經過(A=A.swf, B=B.swf):A透過load()方法載入外部的B並將其附加在Display Object Container中,因為一個swf檔只能有一個舞台,所以B可存取其root物件,但無法存取stage物件,除非被載入的B被加入A的Display List才可以正常存取stage物件,但B在被加入A的Display List前可能就已經呼叫stage的方法或屬性(常發生在建構式),所以才會產生存取null的屬性或是方法的問題

三、解決方法

解決問題的原則就是避免在取得stage物件前呼叫其屬性及方法,AS 3.0提供Event.ADD_TO_STAGE事件,當物件被加入Display List時即會觸發,只要我們將存取stage的程式碼移至ADD_TO_STAGE事件發生之後,就可以確保在存取stage時它不會是null值,就可以避免#1009的問題發生了,底下圖4和圖5大略說明問題解決的方式

圖4 修改前


圖5 修改後 

留言

這個網誌中的熱門文章

【海外婚紗】道具行李篇

[Android] layout_weight的妙用-讓View的大小以百分比率顯示(proportionate size)