通信は、モジュールと親アプリケーションの間、および複数のモジュールの間で行うことができます。次の方法を使用すると、モジュール間の通信、アプリケーションからモジュールへの通信、およびモジュールからアプリケーションへの通信を容易に行うことができます。
次のメソッドおよびプロパティのアクセス方法は、モジュールと同様に親アプリケーションにも適用されます。モジュールは他のモジュールをロードできます。これにより、ロード元のモジュールは親アプリケーションの簡単な例のようになります。
モジュールのメソッドおよびプロパティには、そのモジュールの親アプリケーションからアクセスできます。このためには、そのモジュールのクラスのインスタンスを取得する必要があります。
ModuleLoader を使用してモジュールをロードする場合は、ModuleLoader の child プロパティを参照してモジュールのクラスにキャストすることで、親アプリケーションからモジュールのメソッドを呼び出すことができます。child プロパティはモジュールのクラスのインスタンスです。この場合、モジュールのクラスはモジュールを定義する MXML ファイルの名前です。
次の例では、モジュールの getTitle() メソッドを親アプリケーションから呼び出しています。
親アプリケーション:
<?xml version="1.0"?>
<!-- modules/ParentApplication.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
[Bindable]
private var s:String;
private function getTitle():void {
s = (m1.child as ChildModule1).getModTitle();
}
]]></mx:Script>
<mx:Label id="l1" text="{s}"/>
<mx:ModuleLoader url="ChildModule1.swf" id="m1" ready="getTitle()"/>
</mx:Application>
前の例で実行する SWF ファイルは以下のとおりです。
モジュール:
<?xml version="1.0"?>
<!-- modules/ChildModule1.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
<mx:Script><![CDATA[
// Defines the method that the application calls.
public function getModTitle():String {
return "Child Module 1";
}
]]></mx:Script>
</mx:Module>
この方法を使用すると、アプリケーションとモジュールとが強く結合され、複数のモジュールをロードするときに同じコードを簡単に使用できなくなります。別の方法は、インターフェイスを使用して、アプリケーションが呼び出すことのできるメソッドおよびプロパティをモジュール(またはモジュールのグループ)に定義することです。詳細については、モジュールの通信用インタフェースの使用を参照してください。
ModuleManager API を使用して呼び出す必要があるモジュールをロードする場合は、シェルアプリケーションに追加のコーディングが必要になります。ModuleManager の factory プロパティを使用して、モジュールのクラスのインスタンスを取得します。次に、そのインターフェイスでモジュールのメソッドを呼び出すことができます。
次のモジュールの例では、computeAnswer() という 1 つのメソッドを定義しています。
<?xml version="1.0"?>
<!-- modules/mxmlmodules/SimpleModule.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
public function computeAnswer(a:Number, b:Number):Number {
return a + b;
}
]]>
</mx:Script>
</mx:Module>
次の例では、factory プロパティを使用して SimpleModule クラスのインスタンスを取得し、create() メソッドを呼び出しています。その後、そのインスタンスの computeAnswer() メソッドを呼び出します。
<?xml version="1.0"?>
<!-- modules/mxmlmodules/SimpleMXMLApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import mx.modules.IModuleInfo;
import mx.modules.ModuleManager;
public var assetModule:IModuleInfo;
public var sm:Object;
[Bindable]
public var answer:Number = 0;
public function initApp():void {
// Get the IModuleInfo interface for the specified URL.
assetModule = ModuleManager.getModule("SimpleModule.swf");
assetModule.addEventListener("ready", getModuleInstance);
assetModule.load();
}
public function getModuleInstance(e:Event):void {
// Get an instance of the module.
sm = assetModule.factory.create() as SimpleModule;
}
public function addNumbers():void {
var a:Number = Number(ti1.text);
var b:Number = Number(ti2.text);
// Call a method on the module.
answer = sm.computeAnswer(a, b).toString();
}
]]>
</mx:Script>
<mx:Form>
<mx:FormHeading label="Enter values to sum."/>
<mx:FormItem label="First Number">
<mx:TextInput id="ti1" width="50"/>
</mx:FormItem>
<mx:FormItem label="Second Number">
<mx:TextInput id="ti2" width="50"/>
</mx:FormItem>
<mx:FormItem label="Result">
<mx:Label id="ti3" width="100" text="{answer}"/>
</mx:FormItem>
<mx:Button id="b1" label="Compute" click="addNumbers()"/>
</mx:Form>
</mx:Application>
前の例で実行する SWF ファイルは以下のとおりです。
この例では、Module クラスを拡張する MXML ベースのモジュールではなく、ActionScript の ModuleBase クラスを拡張するモジュールを実際に作成する必要があります。これは、この例にはビジュアルエレメントがなく、値を計算して返す 1 つのメソッドしか含んでいないからです。ModuleBase クラスを拡張するモジュールは、Module を拡張するクラスよりも軽量です。ModuleBase クラスを拡張する ActionScript ベースのモジュールの記述の詳細については、ActionScript ベースのモジュールの作成を参照してください。
モジュールは、parentApplication プロパティへの参照を使用して親アプリケーションのプロパティおよびメソッドにアクセスできます。
次の例では、モジュールが最初にロードされたときに親アプリケーションの expenses プロパティにアクセスしています。モジュールは、次に ArrayCollection であるこのプロパティをグラフのデータのソースとして使用します。ユーザーがボタンをクリックすると、モジュールは、グラフの新しい ArrayCollection を返す親アプリケーションの getNewData() メソッドを呼び出します。
<?xml version="1.0"?>
<!-- modules/ChartChildModule.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" creationComplete="getDataFromParent()">
<mx:Script><![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var expenses:ArrayCollection;
// Access properties of the parent application.
private function getDataFromParent():void {
expenses = parentApplication.expenses;
}
]]></mx:Script>
<mx:ColumnChart id="myChart" dataProvider="{expenses}">
<mx:horizontalAxis>
<mx:CategoryAxis
dataProvider="{expenses}"
categoryField="Month"
/>
</mx:horizontalAxis>
<mx:series>
<mx:ColumnSeries
xField="Month"
yField="Profit"
displayName="Profit"
/>
<mx:ColumnSeries
xField="Month"
yField="Expenses"
displayName="Expenses"
/>
</mx:series>
</mx:ColumnChart>
<mx:Legend dataProvider="{myChart}"/>
<mx:Button id="b1" click="expenses = parentApplication.getNewData();" label="Get New Data"/>
</mx:Module>
次のコードは、前の例のモジュールが使用する親アプリケーションの例です。
<?xml version="1.0"?>
<!-- modules/ChartChildModuleLoader.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var expenses:ArrayCollection = new ArrayCollection([
{Month:"Jan", Profit:2000, Expenses:1500},
{Month:"Feb", Profit:1000, Expenses:200},
{Month:"Mar", Profit:1500, Expenses:500}
]);
public function getNewData():ArrayCollection {
return new ArrayCollection([
{Month:"Apr", Profit:1000, Expenses:1100},
{Month:"May", Profit:1300, Expenses:500},
{Month:"Jun", Profit:1200, Expenses:600}
]);
}
]]></mx:Script>
<mx:ModuleLoader url="ChartChildModule.swf" id="m1"/>
</mx:Application>
前の例で実行する SWF ファイルは以下のとおりです。
メソッドを呼び出して、他のモジュールのプロパティにアクセスすることもできます。詳細については、他のモジュールからのモジュールへのアクセスを参照してください。
この方法の欠点は、親アプリケーションに対する依存関係がモジュール内に作成される可能性があることです。また、アプリケーションの動作を確実に複製しない限り、複数のアプリケーション間でこのモジュールを移植できなくなります。
これらの欠点を回避するには、アプリケーションとそのモジュールの間の約束ごとをセキュリティ保護するインターフェイスを使用する必要があります。この約束ごとでは、アクセスできるメソッドおよびプロパティが定義されます。インターフェイスを使用すると、インターフェイスの最新の状態が維持されている間は、アプリケーションとモジュールを再利用できます。詳細については、モジュールの通信用インタフェースの使用を参照してください。
他のモジュールのプロパティおよびメソッドには、親アプリケーションを介して他のモジュールへの参照を使用することでアクセスできます。そのためには、ModuleLoader の child プロパティを使用します。このプロパティはモジュールのクラスのインスタンスを指しており、これによりメソッドの呼び出しやプロパティへのアクセスが行えるようになります。
次の例では、2 つのモジュールをロードする 1 つのアプリケーションを定義しています。InterModule1 モジュールではストリングを返すメソッドが定義されます。InterModule2 モジュールはそのメソッドを呼び出して、そのモジュールの Label の値をそのメソッドの戻り値に設定します。
メインアプリケーション:
<?xml version="1.0"?>
<!-- modules/InterModuleLoader.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script><![CDATA[
]]></mx:Script>
<mx:ModuleLoader url="InterModule1.swf" id="m1"/>
<mx:ModuleLoader url="InterModule2.swf" id="m2"/>
</mx:Application>
前の例で実行する SWF ファイルは以下のとおりです。
モジュール 1:
<?xml version="1.0"?>
<!-- modules/InterModule1.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
<mx:Script><![CDATA[
// Defines the method that the other module calls.
public function getNewTitle():String {
return "New Module Title";
}
]]></mx:Script>
</mx:Module>
モジュール 2:
<?xml version="1.0"?>
<!-- modules/InterModule2.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
<mx:Script><![CDATA[
[Bindable]
private var title:String;
// Call method of another module.
private function changeTitle():void {
title = parentApplication.m1.child.getNewTitle();
}
]]></mx:Script>
<mx:HBox>
<mx:Label id="l1" text="Title: "/>
<mx:Label id="myTitle" text="{title}"/>
</mx:HBox>
<mx:Button id="b1" label="Change Title" click="changeTitle()"/>
</mx:Module>
この例のアプリケーションを使用すると、2 つのモジュールが相互に通信できるようになります。ただし、メソッドやプロパティは、モジュールがアクセスできるアプリケーションにしか定義できません。詳細については、モジュールからの親アプリケーションへのアクセスを参照してください。
親アプリケーションのプロパティおよびメソッドに直接アクセスする場合と同様に、ここで説明した手法を使用すると、モジュールの再利用が困難になり、モジュールを必要以上に大きくする原因となる依存関係が作成される可能性もあります。代わりに、インターフェイスを使用してモジュール間の約束ごとを定義することをお勧めします。詳細については、モジュールの通信用インタフェースの使用を参照してください。
モジュールにデータを渡す方法の 1 つは、モジュールのロード元に使用する URL にクエリ文字列パラメータを追加することです。そうすれば、ActionScript を使用してクエリ文字列を解析し、データにアクセスできます。
モジュールでは、loaderInfo プロパティを使用してその URL にアクセスできます。このプロパティは、ロード元の SWF(この場合はシェルアプリケーション)の LoaderInfo オブジェクトを指しています。LoaderInfo オブジェクトで提供される情報には、ロードの進行状況、ロードする側とロードされる側のコンテンツの URL、アプリケーションのファイルサイズ、アプリケーションの高さと幅などが含まれます。
次の例では、アプリケーションがロードするモジュールの一意のクエリ文字列がアプリケーションによって作成されます。このクエリ文字列には、firstName パラメータと lastName パラメータが含まれています。
<?xml version="1.0"?>
<!-- modules/QueryStringApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" height="500" width="400">
<mx:Script><![CDATA[
public function initModule():void {
// Build query string so that it looks something like this:
// "QueryStringModule.swf?firstName=Nick&lastName=Danger"
var s:String = "QueryStringModule.swf?" + "firstName=" +
ti1.text + "&lastName=" + ti2.text;
// Changing the url property of the ModuleLoader causes
// the ModuleLoader to load a new module.
m1.url = s;
}
]]></mx:Script>
<mx:Form>
<mx:FormItem id="fi1" label="First Name:">
<mx:TextInput id="ti1"/>
</mx:FormItem>
<mx:FormItem id="fi2" label="Last Name:">
<mx:TextInput id="ti2"/>
</mx:FormItem>
</mx:Form>
<mx:ModuleLoader id="m1"/>
<mx:Button id="b1" label="Submit" click="initModule()"/>
</mx:Application>
前の例で実行する SWF ファイルは以下のとおりです。
次の例では、モジュールをロードするために使用されたクエリ文字列がモジュールによって解析されます。firstName パラメータと lastName パラメータが設定されていると、その結果がモジュールによって TextArea に出力されます。このモジュールは、LoaderInfo オブジェクトを介して使用できるいくつかの追加情報のトレースも行います。
<?xml version="1.0"?>
<!-- modules/QueryStringModule.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="parseString()">
<mx:Script>
<![CDATA[
import mx.utils.*;
[Bindable]
private var salutation:String;
public var o:Object = {};
public function parseString():void {
try {
// Remove everything before the question mark, including
// the question mark.
var myPattern:RegExp = /.*\?/;
var s:String = this.loaderInfo.url.toString();
s = s.replace(myPattern, "");
// Create an Array of name=value Strings.
var params:Array = s.split("&");
// Print the params that are in the Array.
var keyStr:String;
var valueStr:String;
var paramObj:Object = params;
for (keyStr in paramObj) {
valueStr = String(paramObj[keyStr]);
ta1.text += keyStr + ":" + valueStr + "\n";
}
// Set the values of the salutation.
for (var i:int = 0; i < params.length; i++) {
var tempA:Array = params[i].split("=");
if (tempA[0] == "firstName") {
o.firstName = tempA[1];
}
if (tempA[0] == "lastName") {
o.lastName = tempA[1];
}
}
if (StringUtil.trim(o.firstName) != "" &&
StringUtil.trim(o.lastName) != "") {
salutation = "Welcome " +
o.firstName + " " + o.lastName + "!";
} else {
salutation = "Full name not entered."
}
} catch (e:Error) {
trace(e);
}
// Show some of the information available through loaderInfo:
trace("AS version: " + this.loaderInfo.actionScriptVersion);
trace("App height: " + this.loaderInfo.height);
trace("App width: " + this.loaderInfo.width);
trace("App bytes: " + this.loaderInfo.bytesTotal);
}
]]>
</mx:Script>
<mx:Label text="{salutation}"/>
<mx:TextArea height="100" width="300" id="ta1"/>
</mx:Module>
この例では、String クラスと StringUtil クラスのメソッド、および for-in ループを使用して、URL を解析しています。URL の解析は、URLUtil クラスや URLVariables クラスのメソッドを使用してもできます。
モジュールは、クエリ文字列を含むモジュールの URL によってキャッシュされます。したがって、URL を変更したり、URL のクエリ文字列パラメータのいずれかを変更したりすると、新しいモジュールがロードされます。これは、ロードされるモジュールに URL で渡すパラメータに応じて、モジュールの複数のインスタンスが必要な場合に役立ちます。
インターフェイスを使用すると、モジュールからアプリケーションへの通信を提供できます。モジュールにインターフェイスを実装して、アプリケーションでそのインターフェイスのメソッドを呼び出したり、そのインターフェイスのプロパティを設定したりします。インターフェイスには、アプリケーションとモジュールで共有する必要があるメソッドおよびプロパティのスタブを定義します。アプリケーションにとって既知のインターフェイスをモジュールに実装するか、モジュールにとって既知のインターフェイスをアプリケーションに実装します。これにより、モジュールとアプリケーションの間の強い依存関係を回避できます。
メインアプリケーションでモジュールのメソッドを呼び出す必要がある場合は、ModuleLoader の child プロパティをカスタムインターフェイスのインスタンスにキャストします。
次の例では、アプリケーションがロードするモジュールの外観を、カスタム IModuleInterface インターフェイスのメソッドを呼び出すことでカスタマイズできます。このアプリケーションでは getModuleName() メソッドも呼び出されます。このメソッドは、モジュールからの値を返して、ローカルのプロパティをその値に設定します。
<?xml version="1.0"?>
<!-- modules/interfaceexample/MainModuleApp.mxml -->
<mx:Application xmlns="*" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
[Bindable]
public var selectedItem:Object;
[Bindable]
public var currentModuleName:String;
private function applyModuleSettings(e:Event):void {
// Cast the ModuleLoader's child to the interface.
// This child is an instance of the module.
// You can now call methods on that instance.
var ichild:* = mod.child as IModuleInterface;
if (mod.child != null) {
// Call setters in the module to adjust its
// appearance when it loads.
ichild.setAdjusterID(myId.text);
ichild.setBackgroundColor(myColor.selectedColor);
} else {
trace("Uh oh. The mod.child property is null");
}
// Set the value of a local variable by calling a method
// on the interface.
currentModuleName = ichild.getModuleName();
}
private function reloadModule():void {
mod.unloadModule();
mod.loadModule();
}
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="Current Module:">
<mx:Label id="l1" text="{currentModuleName}"/>
</mx:FormItem>
<mx:FormItem label="Adjuster ID:">
<mx:TextInput id="myId" text="Enter your ID"/>
</mx:FormItem>
<mx:FormItem label="Background Color:">
<mx:ColorPicker id="myColor"
selectedColor="0xFFFFFF"
change="reloadModule()"
/>
</mx:FormItem>
</mx:Form>
<mx:Label text="Long Shot Insurance" fontSize="24"/>
<mx:ComboBox
labelField="label"
close="selectedItem=ComboBox(event.target).selectedItem"
>
<mx:dataProvider>
<mx:Object label="Select Module"/>
<mx:Object label="Auto Insurance" module="AutoInsurance.swf"/>
</mx:dataProvider>
</mx:ComboBox>
<mx:Panel width="100%" height="100%">
<mx:ModuleLoader id="mod"
width="100%"
url="{selectedItem.module}"
ready="applyModuleSettings(event)"
/>
</mx:Panel>
<mx:Button id="b1" label="Reload Module" click="reloadModule()"/>
</mx:Application>
前の例で実行する SWF ファイルは以下のとおりです。
次の例では、2 つの getter と 1 つの setter を含む単純なインタフェースを定義しています。このインターフェイスは、前の例のアプリケーションで使用されています。
// modules/interfaceexample/IModuleInterface
package
{
import flash.events.IEventDispatcher;
public interface IModuleInterface extends IEventDispatcher {
function getModuleName():String;
function setAdjusterID(s:String):void;
function setBackgroundColor(n:Number):void;
}
}
次の例では、前の例でロードされるモジュールを定義しています。このモジュールは、カスタムの IModuleInterface インターフェイスを実装しています。
<?xml version="1.0"?>
<!-- modules/interfaceexample/AutoInsurance2.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" implements="IModuleInterface">
<mx:Panel id="p1"
title="Auto Insurance"
width="100%"
height="100%"
backgroundColor="{bgcolor}"
>
<mx:Label id="myLabel" text="ID: {adjuster}"/>
</mx:Panel>
<mx:Script>
<![CDATA[
[Bindable]
private var adjuster:String;
[Bindable]
private var bgcolor:Number;
public function setAdjusterID(s:String):void {
adjuster = s;
}
public function setBackgroundColor(n:Number):void {
// Use a bindable property to set values of controls
// in the module. This ensures that the property will be set
// even if Flex applies the property after the module is
// loaded but before it is rendered by the player.
bgcolor = n;
// Don't do this. The backgroundColor style might not be set
// by the time the ModuleLoader triggers the READY
// event:
// p1.setStyle("backgroundColor", n);
}
public function getModuleName():String {
return "Auto Insurance";
}
]]>
</mx:Script>
</mx:Module>
一般に、モジュール内のコントロールのプロパティを外部の値を使用して設定する場合は、バインド可能な変数を作成する必要があります。次に、それらの変数の値をインターフェイスに実装されたメソッドで設定します。外部の値を使用してモジュールのコントロールのプロパティを直接設定する場合は、モジュールがロードされてプロパティを設定する試みに失敗するまで、そのコントロールはインスタンス化されない場合があります。
このページに新しいコメントが追加された場合に、電子メールでの通知を希望する。 | コメントレポート