サイトトップ

Director Flash 書籍 業務内容 プロフィール

Macromedia Flash非公式テクニカルノート

TLFテキストのある外部SWFを読込むとその中のオブジェクトにアクセスできない

ID: FN1104003 Product: Flash CS5 and above Platform: All Version: 10.1 and above/ActionScript 3.0

問題
[TLFテキスト]が含まれた外部SWFファイルを読込むと、その中にあるオブジェクトの参照が読込んだムービー側のタイムラインから得られないという問題です。

たとえば、外部ファイルとして読込ませるムービーのメインタイムラインに[TLFテキスト]を置いて、my_txtというインスタンス名をつけます(図001)。ファイル名はsub.flaとして、SWFファイルを書出しておきます。

図001■外部ファイルとして読込むムービーのタイムラインに置いた[TLFテキスト]にインスタンス名をつける
図001左図 図001右図

外部SWFファイルを読込むムービーファイルは、同じ階層に保存しておきます。メインタイムラインには、つぎのようなフレームアクションを書きます。外部SWFをLoaderクラスによりロードする、ごく標準的なスクリプトです(図002上図・中図)。ところが、[ムービープレビュー]を確かめると、[TLFテキスト](TLFTextField)インスタンスが見つからないというランタイムエラーが[出力]されます(図002下図)。

var myLoader:Loader = new Loader();
var myInfo:LoaderInfo = myLoader.contentLoaderInfo;
var myURL:URLRequest = new URLRequest("sub.swf");
myInfo.addEventListener(Event.COMPLETE, xLoaded);
myLoader.load(myURL);
addChild(myLoader);
function xLoaded(eventObject:Event):void {
  var my_mc:MovieClip = myLoader.content as MovieClip;
  my_mc.my_txt.text = "success";   // インスタンスmy_txtが見つからない
}

図002■Loaderクラスで読込んだSWFのメインタイムラインにあるインスタンスが参照できない
図002上図

図002中図

図002下図

読込まれるsub.swfに置いた[TLFテキスト]を[クラシックテキスト](TextField)インスタンスに変えると、読込むフレームアクションはそのままで、インスタンスにアクセスできるようになります(図003)。

図003■[TLFテキスト]インスタンスを[クラシックテキスト]に変えると参照できる
図003上左図 図003上右図
図003下図

原因
読込まれるSWFファイルに[TLFテキスト]インスタンスが含まれていると、そのメインタイムラインとそれを読込んだLoaderインスタンスの間に他のインスタンスが加わるようです。たとえば、読込まれるSWFのFLAファイルsub.flaのメインタイムラインに、つぎのようなフレームアクションを1行書き加えます。

trace(this, parent, parent.parent, parent.parent.parent);

読込むムービーのフレームアクションも、LoaderInfo.completeイベント(定数Event.COMPLETE)のリスナー関数からランタイムエラーになるステートメントはコメントアウトして、Loader.contentプロパティの参照を[出力]してみます。

図004■Loader.contentプロパティの参照を[出力]する
図004

読込んだムービーのリスナー関数と、読込まれた外部SWFファイルのフレームアクションから、それぞれ1行ずつ[出力]が示されます。その内容は、Flash Professional CS5と5.5では異なります。備わっているText Layout Frameworkコンポーネントライブラリのバージョンが違うからです[*1]

Flash Professional CS5の場合
Flash Professional CS5では[出力]パネルにつぎのように表示されます。

complete [object MainTimeline__Preloader__]
[object MainTimeline] [object Loader] [object MainTimeline__Preloader__] [object Loader]

つまり、読込んだLoaderインスタンス([object Loader])と読込まれた外部SWFファイルのメインタイムライン([object MainTimeline])の間に、ふたつのインスタンス([object Loader]と[object MainTimeline__Preloader__])ができあがっています。Loader.contentプロパティがロードしたSWFファイルのメインタイムラインを参照していませんので、プロパティからではメインタイムラインに配置したインスタンスにアクセスできないのです。

Flash Professional CS5.5の場合
Flash Professional CS5.5では[出力]パネルの表示はつぎのように変わります。

complete [object MainTimeline__Preloader__]
[object MainTimeline] [object MainTimeline__Preloader__] [object Loader] [object MainTimeline]

1行目はCS5と同じで、Loader.contentプロパティの参照がプリローダのインスタンス([object MainTimeline__Preloader__])になっています。けれど、2行目はCS5と違って、外部SWFのメインタイムラインはプリローダの直接の子で、別のLoaderインスタンス([object Loader])は間に入りません。

いずれにしても、LoaderInfo.completeイベントが起こったときのLoader.contentプロパティはプリローダを参照していますので、プロパティから外部SWFのメインタイムラインにはアクセスできないということです。なお、Flash Professional CS5と5.5でTLFテキストの初期化プロセスが異なることについては、「TLFテキストが配置されたメインタイムラインの初期化」をご参照ください。

[*1] Text Layout Frameworkの仕組みとその使い方については、Adobe Developer Connection「ActionScript 3.0でFlash Professional CS5の Text Layout Frameworkを使う」をご参照ください。


対処法
Loaderインスタンスと読込まれるSWFファイルのメインタイムラインの間に入るインスタンスについては、Adobeの公式ドキュメントに説明が見当たらず、それらの生成のタイミングもはっきりしません。それでも、対応の仕方はいくつか考えられます[*2]。本稿では3つご紹介します。

第1に、外部SWFの表示リストはTLFテキストを初期化する過程で動いても、読込むローダー側はそうした問題がありません[*3]。すると、読込まれるSWFファイルの側から、読込むムービーにメインタイムラインの参照を渡すことが考えられます。つまり、ローダー側ムービーのメインタイムラインに関数を定義して、外部SWFファイルはその関数の引数に自らのメインタイムラインの参照を渡します。

外部SWFファイルを読込むムービーのフレームアクションには、つぎのスクリプト001のように、関数xSetContent()を加えました。この関数は、外部SWFファイルから呼出されて、そのメインタイムラインの参照を受取ります。

スクリプト001■外部SWFから呼出されてメインタイムラインの参照を受取る関数追加

// 外部SWFファィルを読込むムービー: メインタイムライン
var myLoader:Loader = new Loader();
var myInfo:LoaderInfo = myLoader.contentLoaderInfo;
var myURL:URLRequest = new URLRequest("sub.swf");
myInfo.addEventListener(Event.COMPLETE, xLoaded);
myLoader.load(myURL);
addChild(myLoader);
function xLoaded(eventObject:Event):void {
  var my_mc:MovieClip = myLoader.content as MovieClip;
  trace(eventObject.type, my_mc);
}
function xSetContent(my_mc:MovieClip) {
  trace(my_mc, my_mc.my_txt);   // 確認用
  my_mc.my_txt.text = "success";
}

つぎに、読込まれるSWFファィルのメインタイムラインにフレームアクションを書き加えます。Loaderインスタンスとの間につくられるインスタンスの情報が確かではありませんので、読込むロード側ムービーのタイムラインを相対参照することは避けます[*4]。特別の事情がないかぎり、ロード側ムービーのメインタイムラインは、Stageオブジェクトの最初の子です。したがって、DisplayObject.stageプロパティから、DisplayObjectContainer.getChildAt()メソッドで得られるでしょう(スクリプト002)。

スクリプト002■外部SWFファィルのメインタイムラインからロード側ムービーの関数を呼出す

// 外部SWFファイル: メインタイムライン
var myStage:Stage = stage;
var maintimeline:MovieClip = stage.getChildAt(0) as MovieClip;
var callback:Function = maintimeline.xSetContent;
if (callback is Function) {
  callback(this);
}

この読込まれる外部SWFファイルを単独で書出すと、関数が定義されていない旨のランタイムエラーが示されます(図005)。しかし、このエラーは外部SWFファイルとしてロード側ムービーに読込めば解消されます。ロード側ムービーから[ムービープレビュー]を確かめれば、外部SWFファイルのメインタイムラインの参照が得られ、そこに置いたインスタンスにもアクセスできます。

図005■読込まれる外部SWFファィルを単独で書出すとランタイムエラーが示される
図005

対処法の第2は、Text Layout FrameworkのActionScriptライブラリをSWFファイルに埋込むことです。具立て的な手順は、「TLFテキストが配置されたメインタイムラインの初期化」の04「[TLFテキスト]のActionScriptライブラリをSWFに埋込む」をお読みください(なお、「TLF テキストを含む SWF ファイルのパブリッシュ」参照)。

対処法の第3として、SafeLoaderクラスを使うことが挙げられます。SafeLoaderクラスは、この問題に対処するためAdobeから無償で提供されています。そのインストール方法や使い方は、「SafeLoaderクラスを使う」に解説しましたので、お読みください。

[*2] Adobe「Loading child SWFs with TLF content generates reference errors」は、エラーの生じる具体的な状況の説明はないものの、本稿と同じ問題を念頭においているものと思われます。この解説では、本文「対処法」の第2と第3を紹介しています。

なお、jeffkamerer.com「Problems loading child SWFs that use TLF text」は「Custom preloader loop work around」の項でもうひとつ、[パブリッシュ設定]の[ActionScript 3.0の詳細設定]で[プリローダー方式]を[タイムラインのプリローダーループ]にして、カスタムプリローダをつくる方法も紹介しています。日本語の記事としては、2BLOG「ランタイム共有ライブラリのさらなるローディング方法」が参考になります。

[*3] 読込む側のムービーにもTLFテキストを置いた場合には、表示リストが組替えられてしまうので、問題が起きそうです。けれど、ローダー側ムービーのフレームアクションが実行されるのは、TLFテキストの初期化が済んだ後です。したがって、ほかに表示リストにおけるメインタイムラインの位置を動かしていなければ、[1]の処理に問題は生じません。

[*4] Flash Professional CS5の[ムービープレビュー]で確かめると、読込まれたSWFファィルにはさらにDisplayObject.addedToStageイベント(定数Event.ADDED_TO_STAGE)が起こり、つぎのようにLoaderオブジェクトとの間に入るインスタンスの数はひとつに減ります(図006)。

addedToStage [object MainTimeline] [object MainTimeline__Preloader__] [object Loader]

addEventListener(Event.ADDED_TO_STAGE, xAdded);
function xAdded(eventObject:Event):void {
  trace(eventObject.type, this, parent, parent.parent);   // インスタンスの階層を確認
}

図006■読込まれる外部SWFファィルにDisplayObject.addedToStageイベントのリスナー関数を加える
図005

なお、この動きはCS5.5では異なります。詳しくは前出「TLFテキストが配置されたメインタイムラインの初期化」の01「メインタイムラインはどこにいるのか」をご参照ください。


作成者: 野中文雄
更新日: 2012年1月3日 Flash Professional CS5.5の情報や「SafeLoaderクラスを使う」へのリンクなどを追加。
作成日: 2011年4月18日


Copyright © 2001-2012 Fumio Nonaka.  All rights reserved.