doOperation()メソッドの追加
doOperation()
メソッドはユーザーの指示に従って、加減乗除のいずれかの処理を行います。なお、演算処理を行う前には、ActionScript内蔵のNumber()
メソッドを利用して、reg1
とreg2
の値を数値データ型に成型してから、それぞれr1
プロパティとr2
プロパティに代入します。
どの演算処理を行うかは、switch-case
構文で分岐します。次にActionScriptのswich-case
構文を示します。
switch (expression) { case value: [ActionScriptのステートメント] break; // この行がなければ次のケースに処理が進みます [その他のケース] default: [デフォルトのケース処理] }
ActionScriptにおける加減乗除の演算子は次のとおりです。
+ - * /
次の手順に従って、doOperation()
メソッドを追加します。
- コンストラクタ関数の後に
public
メソッドのdoOperation
を作成し、このメソッドの引数や戻り値は「なし」に設定しておきます。 - このメソッドのブロックのはじめに、
reg1
、reg2
の値を数値型に成型し、それぞれthis.r1
、this.r2
に代入します。 operation
プロパティの値を元に分岐するswitch-case
を追加します。switch
ブロックの中にadd
、subtract
、multiply
、divide
の4つの演算処理用のケースを追加します。各ケースの中には、r1
とr2
に対して適切な演算を行った結果をresult
プロパティに代入するための式と、resetAfterOp()
メソッドの呼び出しを含め、それぞれのケースをbreak
ステートメントで閉じます。- 一切の処理を行わない
default
のケース(演算処理が設定されていない場合のため)も設定しておきます。
public function doOperation():Void { }
this.r1=Number(reg1); this.r2=Number(reg2);
switch (operation)
{
}
case "add": this.result=r1+r2; resetAfterOp(); break; case "subtract": this.result=r1-r2; resetAfterOp(); break; case "multiply": this.result=r1*r2; resetAfterOp(); break; case "divide": this.result=r1/r2; resetAfterOp(); break;
default: // 何もしない
addNumber()メソッドの追加
addNumber()
メソッドは電卓アプリケーションのビューから渡された数字を文字列として受け取り、この文字列後ろに現在のレジスタの文字列を付加します。ActionScriptの(+
)演算子は多重処理をサポートしているので、オペランド同士が文字列の場合はこれらを結合します。
結合処理自体は簡単ですが、ここでは特別な場面を想定する必要があります。メソッドが演算処理を行った後には、演算結果をreg1
にコピーしてから、reg2
を現在のレジスタとして設定し、演算結果に対してさらなる演算処理が行われることに対処する必要があります。しかし、ユーザーが結果に対して新たな演算を行わず、代わりに新たな数字を入力する場合は、reg1
の内容を消去してreg1
を現在のレジスタに設定する必要があります。
このような条件のチェックを行い、正しい処理を行うにはif
文を使用する必要があります。また、ここでは2重の条件をチェックするので、ActionScriptのAND論理演算子、「&&
」を使用します(なおOR論理演算子は「||
」)。次にif-else
の標準構文を示します。
if (condition[s]) { [ActionScript のステートメント] }[else if (condition) // 0 またはそれ以上 { [ActionScript のステートメント] }else // 0 または 1 { [ActionScript のステートメント] }]
次にActionScriptの比較演算子を示します。
演算子 | 意味 |
== | 等価 |
< | より小さい |
> | より大きい |
<= | より小さいか等しい |
>= | より大きいか等しい |
! | 否定(NOT) |
このメソッドを作成する際にもう1つ必要なActionScriptの概念は、「ランタイム時の動的評価」です。現在のレジスタがどちらのレジスタであるかは、後ほど作成するsetCurrentRegister()
メソッドによってランタイム時に動的に設定します。現在のレジスタがどちらであるかはthis[currentRegister]
式を利用することで取得でき、currentRegister
プロパティは常にreg1
またはreg2
のいずれかのレジスタプロパティ名になります。オブジェクト参照の後にある角括弧([ ]
)はランタイム時に強制的に動的な評価を実行することを意味し、これを利用することでプロパティ名を動的に設定もしくは取得することができます。
doOperation()
メソッドの後にpublic
メソッドのaddNumber()
を作成して、文字列の引数n
を受け付けるようにし、戻り値をなしに設定します。- このメソッドブロックの中に
if
文を追加し、operation
プロパティの値が「none」であり、なおかつcurrentRegister
プロパティが「reg2」であることを評価します。
public function addNumber(n:String):Void { }
if (operation=="none" && currentRegister=="reg2") { }
doOperation()
がresetAfterOp()
メソッドを呼び出し、なおかつ、ユーザーが数字のボタンをクリックした場合に「true」になります。if
ブロックの中で、reg1
プロパティに空の文字列を代入してから、setCurrentRegister()
メソッド(後ほど作成します)を呼び出すようにしておきます。if
文の後に、現在のレジスタに「n」の値を付加するためのコードを追加します。setDisplay()
メソッドの呼び出しを追加し、currentRegister
プロパティを引数として渡します(このメソッドは後ほど作成します)。
reg1="";
setCurrentRegister();
this[currentRegister]+=n;
this[currentRegister] = this[currentRegister] + n;
setDisplay(currentRegister);
clearEntry()メソッドとclearAll()メソッドの追加
この2つのシンプルなメソッドは似通っているので、同時に解説します。clearEntry()
メソッドでは現在のレジスタの内容と画面表示を消去するようにし、clearAll()
メソッドでは両方のレジスタの内容と画面表示を消去するとともに、処理待ちの演算を「none」、urrentRegister
プロパティを「reg1」に設定するようにします。
public
メソッドのclearEntry()
を追加し、引数と戻り値をなしに設定します。- このメソッドブロックの中で、現在のレジスタに空の文字列を代入し、さらに
currentRegister
プロパティを引数とするsetDisplay()
メソッドの呼び出しを追加します。 public
メソッドのclearAll()
を追加し、引数と戻り値をなしに設定します。- このメソッドブロックの中では、両方のレジスタに空の文字列を代入し、さらに、引数のない
setCurrentRegister()
の呼び出し、「none」を引数とするsetOperation
の呼び出し、currentRegister
を引数とするsetDisplay
の呼び出しを追加します。
public function clearEntry():Void { }
this[currentRegister]=""; setDisplay(currentRegister);
public function clearAll():Void { }
reg1=""; reg2=""; setCurrentRegister(); setOperation("none"); setDisplay(currentRegister);
setOperation()メソッドの追加
このメソッドは単に値を代入するためだけのものです。ここでは処理待ちの演算を設定し、その後にsetCurrentRegister()
メソッド(後ほど作成)を利用して、現在のレジスタをリセットします。
public
メソッドのsetOperation()
を追加し、String
タイプの引数、operation
を受け付けるようにし、戻り値をなしに設定します。- このメソッドブロックの中では、引数として受け取った
operation
をoperation
プロパティの値に代入し、その後setCurrentRegister()
メソッドを呼び出します。
public function setOperation(operation:String):Void { }
this.operation=operation;
setCurrentRegister();
setDisplay()メソッド、setCurrentRegister()メソッド、resetAfterOp()メソッドの追加
この3つのprivate
メソッドも簡単です。setDisplay()
メソッドは、引数として受け取ったレジスタ名の値を電卓の表示ラベルのtext
プロパティに代入します。setCurrentRegister()
メソッドはreg1
が空の場合はreg1
を現在のレジスタに設定し、それ以外の場合はreg2
を現在のレジスタとして設定します。そしてresetAfterOp()
メソッドは、演算結果をreg1
にコピーし、つぎの演算処理に移れるようにその他の値を設定します。
private
メソッドのsetDisplay()
を追加し、String
タイプの引数、register
を受け付けるようにし、戻り値をなしに設定します。- このメソッドブロックの中で、
calcView.calcDisplay.text
プロパティの値に引数として受け取ったレジスタを代入します。 private
メソッドのsetCurrentRegister()
を追加し、引数と戻り値をなしに設定します。- このメソッドのブロックの中に
if-else
文を追加し、reg1
の値が空ストリングの場合はcurrentRegister
プロパティを「reg1」に設定し、それ以外の場合はcurrentRegister
プロパティを「reg2」に設定するようにします。 private
メソッドのresetAfterOp()
を追加し、引数と戻り値をなしに設定します。- このメソッドブロックの中で、
result
の現在の値をreg1
の値に、空の文字列をreg2
にそれぞれ代入します。また、reg1
を引数とするsetDisplay()
の呼び出しと、none
を引数とするsetOperation()
メソッドの呼び出しも追加します。 - ここでファイルを保存しておきます。
private function setDisplay(register:String):Void { }
calcView.calcDisplay.text = this[register];
private function setCurrentRegister():Void { }
if (reg1=="") { currentRegister="reg1"; } else { currentRegister="reg2"; }
private function resetAfterOp():Void { }
reg1=String(result); reg2=""; setDisplay("reg1"); setOperation("none");
CalculatorHandlersクラスのインスタンス化
このチュートリアルの最後のステップは、先程作成したCalculatorHandlers
クラスを「calculator.mxml」ファイル内でインスタンス化することです。この処理はタグを利用してできますが、このタグはFlexクラスライブラリに含まれていないので、新しい名前空間を追加する必要があります。名前空間を追加するには、Application
タグの中に新たなxmlns
プロパティを追加し、このプロパティの値を「"*"」に設定します。この"*"
の値は、アプリケーションディレクトリの中にあるすべてのクラスを要素として受け付けることを指示しています。
なお、ここではCalculatorHandlers
クラスがcalcDisplay
オブジェクトにアクセスできるよう、電卓アプリケーションのApplication
オブジェクトに参照する必要があることに注意してください。この参照情報を渡すには、CalculatorHandlers
オブジェクトのcalcView
プロパティを「{this}」に設定します。MXMLファイルの中のthis
はApplication
オブジェクト全体への参照を意味します。また、波括弧({ }
)は、データバインディングを意味し、Flexコンパイラは括弧内のコンテンツを純粋な文字列ではなく、表現式として評価します。
CalculatorHandlers
オブジェクトには、アプリケーション内のその他の要素が参照できるよう、インスタンス名が必要です。インスタンス名は、クラスをインスタンス化する際に使用するタグのid
属性で設定します。
- 「calculator.mxml」ファイルを開き、
Application
タグの中に新たなxmlns
プロパティを追加し、このプロパティ値に名前空間の値、「"*"」を設定します。この際、接頭辞は不要です。 Application
タグのブロックの始めにCalculatorHandlers
タグを追加し、このタグの属性にid="calcHandlers"
とcalcView="{this}"
を追加します。- ファイルを保存してから、Webブラウザでファイルの動作を確認します。(MXMLファイルのブラウズ方法が分からない場合は、こちらの解説を参照してください。)
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" xmlns="*">
<CalculatorHandlers id="calcHandlers" calcView="{this}"/>
<?xml version="1.0"?> <mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
xmlns="*"> <!-- calculator のコントローラー --> <CalculatorHandlers id="calcHandlers" calcView="{this}"/> <!-- calculator のビュー --> <mx:Panel title="Calculator"> <!-- calculator のディスプレイ --> <mx:Label id="calcDisplay" width="150" textAlign="right"/> <!-- calculator のコントロール群 --> <mx:Grid> <mx:GridRow> <mx:GridItem colSpan="2"> <mx:Button width="70" label="Clear"
click="calcHandlers.clearAll()"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="C/E"
click="calcHandlers.clearEntry()"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="+"
click="calcHandlers.setOperation('add')"/> </mx:GridItem> </mx:GridRow> <mx:GridRow> <mx:GridItem> <mx:Button width="30" label="1"
click="calcHandlers.addNumber('1')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="2"
click="calcHandlers.addNumber('2')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="3"
click="calcHandlers.addNumber('3')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="-"
click="calcHandlers.setOperation('subtract')"/> </mx:GridItem> </mx:GridRow> <mx:GridRow> <mx:GridItem> <mx:Button width="30" label="4"
click="calcHandlers.addNumber('4')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="5"
click="calcHandlers.addNumber('5')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="6"
click="calcHandlers.addNumber('6')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="*"
click="calcHandlers.setOperation('multiply')"/> </mx:GridItem> </mx:GridRow> <mx:GridRow> <mx:GridItem> <mx:Button width="30" label="7"
click="calcHandlers.addNumber('7')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="8"
click="calcHandlers.addNumber('8')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="9"
click="calcHandlers.addNumber('9')"/> </mx:GridItem> <mx:GridItem> <mx:Button width="30" label="/"
click="calcHandlers.setOperation('divide')"/> </mx:GridItem> </mx:GridRow> <mx:GridRow> <mx:GridItem> <mx:Button width="30" label="0"
click="calcHandlers.addNumber('0')"/> </mx:GridItem> <mx:GridItem > <mx:Button width="30" label="."
click="calcHandlers.addNumber('.')"/> </mx:GridItem> <mx:GridItem colSpan="2"> <mx:Button width="70" label="="
click="calcHandlers.doOperation()"/> </mx:GridItem> </mx:GridRow> </mx:Grid> </mx:Panel> </mx:Application>
/*
Calculator Controller
*/ class CalculatorHandlers { // プロパティ // ビューオブジェクトへの参照を保持するためのオブジェクト public var calcView:Object; // 演算処理待ちの一時的な値を保持するためのレジスタ private var reg1:String=""; private var reg2:String=""; // 演算処理の結果 private var result:Number; // 現在使用中のレジスタの名前 private var currentRegister:String="reg1"; // 次に処理する演算の名前 private var operation:String="none"; // レジスタの文字列値を数値に変換して保持 private var r1:Number; private var r2:Number; // コンストラクタ関数 public function CalculatorHandlers() {} // メソッド // 2 つのレジスタに対して現在の指定演算を実行 public function doOperation():Void { // レジスタの値を数値型に成型 r1=Number(reg1); r2=Number(reg2); switch (operation) { case "add": result=r1+r2; resetAfterOp(); break; case "subtract": result=r1-r2; resetAfterOp(); break; case "multiply": result=r1*r2; resetAfterOp(); break; case "divide": result=r1/r2; resetAfterOp(); break; default: // 何もしない } } // 現在のレジスタの値に数字を付加 public function addNumber(n:String):Void { if (operation=="none" && currentRegister=="reg2") { reg1=""; setCurrentRegister(); } this[currentRegister]+=n; setDisplay(currentRegister); } // 現在のレジスタをクリヤー public function clearEntry():Void { this[currentRegister]=""; setDisplay(currentRegister); } // 2 つのレジスタと現在の指定演算をクリヤー public function clearAll():Void { reg1=""; reg2=""; setCurrentRegister(); setOperation("none"); setDisplay(currentRegister); } // 現在の指定演算を設定 public function setOperation(operation:String):Void { this.operation=operation; setCurrentRegister(); } // ディスプレイに表示される値を設定 private function setDisplay(register:String):Void { calcView.calcDisplay.text = this[register]; } // 現在のレジスタがどちらのレジスタであるかを設定 private function setCurrentRegister():Void { if (reg1=="") { currentRegister="reg1"; } else { currentRegister="reg2"; } } // 演算処理後に値をリセット private function resetAfterOp():Void { reg1=String(result); reg2=""; setDisplay("reg1"); setOperation("none"); } }
つぎのステップ
このチュートリアルで作成した電卓アプリケーションはシンプルなものでしたが、このアプリケーションに手を加えれば容易に多彩な機能の備わった電卓アプリケーションが作成できます。またActionScriptには数々の静的Math
クラスが含まれており、これらのメソッドを利用すれば開発時の手間が省けます。ここで重要なのは、これでMXMLとActionScriptの基礎要素の扱い方が習得できたことです。さらに高度なアプリケーションの開発にもチャレンジしてみてください。
是非つぎのチュートリアルに進み、さらにFlexの習得を深めてください。
このチュートリアルの内容にご関心をお持ちいただけた場合は、Flexにデフォルトで含まれているサンプルアプリケーションなども一度目を通すようにしてください。Flexの搭載機能をデモするサンプルが多数収録されています。