がるの健忘録 このページをアンテナに追加 RSSフィード

2009-07-01

[]今更的な話なんだけど…

でも、書籍とかでもあんまり書いてないぞ? 的な話。

プログラマとしては必須といってもイイ情報だし、だからこそ「初歩本の一番手前に書いて欲しい」んだけど…。

ちょいと散文(ちょいと?)。


キャストの仕方。

いわゆる()の演算子…例えば

変数 = (キャストしたい型)別の変数;

は、ないぽ。単純にシンタックスエラーになる。

  var t:Label = new Label;
  var b:Box;
  b = (Box)t; /* シンタックスエラー */

次。いにしえからあるらしいキャスト方法は…クラス名+()演算子。DataType(object)という書式になるです。

なんていうか…newが付いていないだけで、new演算子の書式にごっつ似てるので…要注意。いや割とかなり真剣に悩み&ひっかかりました orz

  var t:Label = new Label;
  var b:Box;
  b = Box(t);

こんなげ。もっとも、これ実行すると

TypeError: Error #1034: 強制型変換に失敗しました。mx.controls::Label@1585f0b1 を mx.containers.Box に変換できません。

ってエラーになるけど。


で、ActionScript3で新しく登場したらしい、as演算子

  var t:Label = new Label;
  var b:Box;
  b = t as Box;
trace (b);

これだと、bにはnullが入る。ちなみにnullのチェックは == で簡単にチェックできる。

nullにならず、ちゃんとキャストできる例は、例えばこんなん。

  var t2 = new VBox;
  var b2:Box;
  b2 = t2 as Box;
trace (b2);

余談。

is演算子ってのがあって、それは「変数が指定されたclassの系譜にいてるかどうか」をチェックするみたいです。

微妙に興味ないので、サンプルだけ簡単に。

http://weblogs.macromedia.com/akamijo/archives/2006/01/is.html

var mySprite:Sprite = new Sprite();

trace (mySprite is Sprite); // true が出力される

trace (mySprite is DisplayObject); // true が出力される

trace (mySprite is IEventDispatcher); // true が出力される

-中略-

var mySprite:Sprite = new Sprite();

trace (mySprite instanceof Sprite); // true が出力される

trace (mySprite instanceof DisplayObject); // false が出力される

trace (mySprite instanceof IEventDispatcher); // false が出力され


次。

インスタンスclass名は、className メソッドがあるです。…まぁ引数で持ってきた時にこのパラメタチェックしてくれてないっぽいので、上述のキャストが色々と必須になる訳なのですが(苦笑

面白いのが、id。

mxmlGUIオブジェクトを作ると、ID名がそのまんまインスタンス名になるですが。

Scriptでnewすると、当然ながらID名はカラッポ(null)になってるです。普通に

  t.id = "t";  

とかでつっこめるので。ユニーク(一意)であることを条件にではありますが、できるだけ、部品にはID名ぶち込んでおいたほうが後々楽だと思う。

いわゆる礼儀とか躾とか嗜みとかってやつですか?

mxml

<mx:VBox id="vvv">
<mx:TextInput id="ti" width="200"  />

Script

trace(  ti.className );
trace(  ti.id );

  var t:Label = new Label;
  t.text = 'text 1';
trace(  t.className );
trace(  t.id );

  t.id = "t";  
trace(  t.className );
trace(  t.id );

次。…基本的にGUIインスタンスってApplicationのクラス変数(?)になるようなのですが。

なので、アクセスは

<mx:TextInput id="ti" width="200"  />

の場合

trace(  this.ti.id );
trace(  ti.id );

というアクセス方法は一般的ですし知られていると思うのですが。

ぢつはもう一つあるです。

  var wk:String = "ti";
trace(  this[wk].id );

まぁびっくり[]演算子使えるですねぇ。


…この辺知ってたら、もっときれいに書けたのに orz


あと。演算子…なんか色々あるですが。PHPと同様、==と===があるぽいです orz

http://livedocs.adobe.com/flex/2_jp/langref/operators.html#equality

2 つの式の等価性をテストします。式が等しい場合、結果は true です。

2 つのオペランドのデータ型が一致する場合、等価の定義はオペランドのデータ型によって決まります。

* int、uint、および Boolean 型の値は、値が同じ場合に等しいと見なされます。

* Number 型は、値が同じで両方とも NaN でない場合に等しいと見なされます。

* 2 つのオペランドの値が null または undefined の場合は、等しいと見なされます。

* ストリング式は、文字数が同じで、同じ文字で構成されている場合に、等しいと見なされます。

* XML オプジェクトの場合 :

o 一方のオペランドがテキストまたは属性ノードで、もう一方のオペランドに単純内容が含まれる場合は、オペランドを両方とも toString() メソッドでストリングに変換し、結果のストリングが一致する場合に等しいと見なされます。

o それ以外の場合、オブジェクトは、両方のオブジェクトの修飾名、属性、および子プロパティが一致する場合にのみ等しいと見なされます。

* XMLList オブジェクトの場合は、プロパティの数が同じで、プロパティの順序および値が一致する場合に等しいと見なされます。

* Namespace オブジェクトの場合は、両方のオブジェクトuri プロパティが一致する場合に値が等しいと見なされます。

* QName オブジェクトの場合は、両方のオブジェクトuri プロパティおよび localName プロパティが一致する場合に値が等しいと見なされます。

* オブジェクト配列、および関数を表す変数は、参照により比較されます。2 つの変数が同じオブジェクト配列、または関数を参照する場合、それらの変数は等価です。2 つの別個の配列は、エレメント数が同じである場合でも、等しいとは見なされません。

オペランドのデータ型が一致しない場合は、次の場合を除き、結果は false になります。

* オペランドの値が undefined および null の場合。この場合、結果は true になります。

* 自動データ型変換により String、Boolean、int、uint、および Number のデータ型の値が互換性のある型に変換され、変換された値が等しい場合。この場合、オペランドは等しいと見なされます。

* 一方のオペランドが単純内容 (hasSimpleContent() == true) を持つ XML 型で、両方のオペランドを toString() メソッドでストリングに変換し、結果のストリングが一致する場合。

* 一方のオペランドが XMLList 型で、次のいずれかの条件に該当する場合。

o XMLList オプジェクトの length プロパティが 0 で、もう一方のオブジェクトが undefined である。

o XMLList オプジェクトの length プロパティが 1 で、XMLList オブジェクトの 1 つのエレメントがもう一方のオペランドに一致する。

おまけ。

http://livedocs.adobe.com/flex/2_jp/langref/operators.html#strict_equality

一回チェックせんと、ですかねぇ…

あと。上述、2なので。本当は

http://livedocs.adobe.com/flex/3_jp/langref/operators.html#equality

とかを見た方が良いと思う…っていう手抜きw


そうそう。演算子一覧はここ。

http://livedocs.adobe.com/flex/3_jp/langref/operators.html


いぢょ ノ

[]Flashとの連携

http://blog.bk-zen.com/2008/03/19/53/

こちらにきれいにまとまってまふ。

とりあえず思うところをつらつら。


1. FlexFlash CS3 では コンパイラが違う。

そうなんだよねぇ…吐き出す中間コードは同じはずなのに orz


あちこちで、多くの人が苦労しているんだなぁと思う orz


[]Drag and Drop 調査:fromオブジェクト

以下、面倒なんでドラッグ&ドロップ(Drag and Drop)をDDと略します。


まず。ドラッグして移動するアイテムをfromオブジェクト、fromオブジェクトを格納する先をtoオブジェクトと仮に呼称しておきます(なんか正式名称あったら速攻切り替えますw)。

オブジェクトとも、mx.core.UIComponentの派生クラスならOKなようです。


で…まず、仕様によらない、DDの考察を。


fromオブジェクト

マウスをクリック(ダウン)して

・そのままの状態でマウスが移動:オブジェクトが移動する


toオブジェクト

・移動中のfromオブジェクトがtoオブジェクトの上空にいる

・その状態でマウスアップ(クリックの指を外す)が発生する

・fromオブジェクトを受け入れる準備が整ったので「かも〜ん」


こんな感じでげしょか?

とりあえず、雑に領域を用意してみましょう。fromオブジェクトにはボタンを、toオブジェクトにはパネルを用意します。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="onComplete()">

<!-- ********************************** -->
<mx:Script source="base.as" />


<!-- ********************************** -->
<mx:Panel>
	
<mx:Panel id="p1" >
</mx:Panel>

<mx:Button id="bt1" label="●" />

</mx:Panel>
	
</mx:Application>

…デザイン? なにそれおいしい?


おいといて。


では。まず「fromオブジェクトをふらふらと動かせる」ようにしてみませう。

fromオブジェクトでは、マウスをクリック(mouseDown)、マウス移動(mouseMove)のほかに。マウスのクリックで手を離してしまった時用にマウスアップ(mouseUp)のイベントを捕捉します。

private function onComplete():void{
  // マウスダウンを捕捉
  bt1.addEventListener(MouseEvent.MOUSE_DOWN, m_down);

  // マウスアップを捕捉
  bt1.addEventListener(MouseEvent.MOUSE_UP, m_up);

  // マウス移動を捕捉
  bt1.addEventListener(MouseEvent.MOUSE_MOVE, m_move);
}

// マウスダウン
private function m_down(e:MouseEvent):void{
  Alert.show("mouse_doun");
}

// マウスアップ
private function m_up(e:MouseEvent):void{
  Alert.show("mouse_up");
}

// マウス移動
private function m_move(e:MouseEvent):void{
  Alert.show("mouse_move");
}

一応動くけど…いやまぁ反応よくて面倒(苦笑

traceにしたほうが、多分試しやすいです。…moveとか凄い量になりそうだけど。


んで。イベントに反応して「実際に動かしてみたい」ので。

ちと小細工します。

動かすので、中核になるのはmoveイベント。

moveイベント内で「マウスダウンが発生したらフラグ立てて動けるようにして、マウスアップを検出したらフラグを寝かせる」ようにします…ので、先にフラグの実装から。


import flash.events.MouseEvent;

import mx.controls.Alert;


private function onComplete():void{
  // マウスダウンを捕捉
  bt1.addEventListener(MouseEvent.MOUSE_DOWN, m_down);

  // マウスアップを捕捉
  bt1.addEventListener(MouseEvent.MOUSE_UP, m_up);

  // マウス移動を捕捉
  bt1.addEventListener(MouseEvent.MOUSE_MOVE, m_move);
}

// マウスダウン
private function m_down(e:MouseEvent):void{
  this.m_flg_ = true;
}

// マウスアップ
private function m_up(e:MouseEvent):void{
  this.m_flg_ = false;
}

// マウス移動
private function m_move(e:MouseEvent):void{
  Alert.show("mouse_move");
}


//private
private var m_flg_:Boolean = false; // マウスダウンでtrueにする

で…動かすには、DragManagerという子にお願いをする必要があるようです。DragManagerのdoDrag()メソッドが必要なようなので…まずは仕様の確認。

public static function doDrag(dragInitiator:IUIComponent, dragSource:DragSource, mouseEvent:MouseEvent, dragImage:IFlexDisplayObject = null, xOffset:Number = 0, yOffset:Number = 0, imageAlpha:Number = 0.5, allowMove:Boolean = true):void

ドラッグ & ドロップ操作を開始します。

パラメータ

dragInitiator:IUIComponent ― ドラッグを開始するコンポーネントを指定する IUIComponent です。

dragSource:DragSource ― ドラッグされているデータを含む DragSource オブジェクトです。

mouseEvent:MouseEvent ― ドラッグを開始するためのマウス情報を含む MouseEvent です。

dragImage:IFlexDisplayObject (default = null) ― ドラッグするイメージ。この引数オプションです。省略した場合、ドラッグ & ドロップ操作時には標準的なドラッグ長方形が使用されます。イメージを指定する場合は、イメージの高さと幅を明示的に設定しないとイメージが表示されません。

xOffset:Number (default = 0) ― dragImage の x オフセットピクセル単位で指定する数値です。この引数オプションです。これを省略すると、ドラッグプロキシドラッグイニシエータの左上隅に表示されます。このオフセットは、ドラッグプロキシの左端からドラッグイニシエータの左端までのピクセル数として表され、通常は負の数値になります。

yOffset:Number (default = 0) ― dragImage の y オフセットピクセル単位で指定する数値です。この引数オプションです。これを省略すると、ドラッグプロキシドラッグイニシエータの左上隅に表示されます。このオフセットは、ドラッグプロキシの上端からドラッグイニシエータの上端までのピクセル数として表され、通常は負の数値になります。

imageAlpha:Number (default = 0.5) ― dragImage に使用されるアルファ値を指定する数値です。この引数オプションです。省略した場合のデフォルトアルファ値は 0.5 です。値が 0.0 の場合、イメージは透明であることを示します。値が 1.0 の場合、イメージは完全な不透明であることを示します。

allowMove:Boolean (default = true)

まず第一パラメタはfromオブジェクトであるbt1を。

第二パラメタは…DragSource って、なんじゃらほい?

DragSource クラスには、ドラッグされるデータが格納されます。このデータには複数の形式が使用されます。たとえば、テキストコンポーネントにはプレーンテキスト、リッチテキスト、HTML データが入ります。

はぁ…つまり「移動させるブツそのものが入る」でよいのかしらん?

いくつか、余所様のサイトから、これに関連するあたりを引っかけてみる。

        var ds:DragSource = new DragSource();
        ds.addData(ddbox, "canvas");
            // DragSource オブジェクトを作成します。
            var ds:DragSource = new DragSource();
            // オブジェクトにデータを追加します。
            ds.addData(text, format);

これ↑はdragIt(event, 'red', 'color')とcallされてる。

            //ドラッグされるデータを作成
            var dragSource:DragSource = new DragSource();
            dragSource.addData(image.source, "img");

第二引数が…よぉわからん。で、調べる。

addData () メソッド

public function addData(data:Object, format:String):void

データ、および対応する形式のストリングをドラッグソースに追加します。このメソッドは値を返しません。

パラメータ

data:Object ― ドラッグデータを指定するオブジェクトです。String、DataProvider など、任意のオブジェクトを使用できます。

format:String ― このデータの形式を記述するラベルを指定するストリングです。

なるほどようはハンドル名らしい。

で…やってみた。

//
import flash.events.MouseEvent;

import mx.core.DragSource;
import mx.managers.DragManager;


private function onComplete():void{
  // マウスダウンを捕捉
  bt1.addEventListener(MouseEvent.MOUSE_DOWN, m_down);

  // マウスアップを捕捉
  bt1.addEventListener(MouseEvent.MOUSE_UP, m_up);

  // マウス移動を捕捉
  bt1.addEventListener(MouseEvent.MOUSE_MOVE, m_move);
}

// マウスダウン
private function m_down(e:MouseEvent):void{
  this.m_flg_ = true;
}

// マウスアップ
private function m_up(e:MouseEvent):void{
  this.m_flg_ = false;
}

// マウス移動
private function m_move(e:MouseEvent):void{
  if (true == this.m_flg_) {
    var ds:DragSource = new DragSource;
    ds.addData(bt1, "bt1");
    DragManager.doDrag(bt1, ds, e);
  }
}


//private
private var m_flg_:Boolean = false; // マウスダウンでtrueにする

をを動く!!


で…このままだと固定値が多くていやなので。

マウスイベントで情報取れないかなぁ…おもってたらついでに一案。マウスダウンだけで実装できね?


まず。マウスイベントは…その中にcurrentTargetってのがあるです。

っつわけで、調査。

// マウスダウン
private function m_down(e:MouseEvent):void{
trace( e.currentTarget );
trace( e.currentTarget.className );
}

DD2_0.Panel4.bt1

Button

ふむり。んでは…がりごりっとテスト実装。

// マウスダウン
private function m_down(e:MouseEvent):void{
  //DragManager.doDrag(bt1, ds, e);
  var ds:DragSource = new DragSource();
  ds.addData(e.currentTarget, "test");
  DragManager.doDrag(e.currentTarget, ds, e);
}

あれ? エラーが出る。どうやら、本当はButton型なのに「やってきたのがObject型だから僕Object型としてしか見なさないモン」と言ってるらしい…融通のきかない orz

とりあえずButtonクラスにキャストしてみる。

// マウスダウン

private function m_down(e:MouseEvent):void{

var b:Button;

b = e.currentTarget as Button;

var ds:DragSource = new DragSource();

ds.addData(e.currentTarget, "test");

DragManager.doDrag(b, ds, e);

}

無問題。で…余所で見たんだけど…DragSourceがどうもいらないくさい。実験くん。

// マウスダウン
private function m_down(e:MouseEvent):void{
  var b:Button;
  b = e.currentTarget as Button;
  DragManager.doDrag(b, new DragSource(), e);
}

よしいける!!

問題がなきゃこのままいきまっしょ。


現状のソース。


mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="onComplete()">

<!-- ********************************** -->
<mx:Script source="base.as" />


<!-- ********************************** -->
<mx:Panel>
	
<mx:Panel id="p1" >
</mx:Panel>

<mx:Button id="bt1" label="●" />

</mx:Panel>
	
</mx:Application>

Script

//
import flash.events.MouseEvent;

import mx.containers.Box;
import mx.controls.Button;
import mx.core.DragSource;
import mx.managers.DragManager;


private function onComplete():void{
  // マウスダウンを捕捉
  bt1.addEventListener(MouseEvent.MOUSE_DOWN, m_down);
}

// マウスダウン
private function m_down(e:MouseEvent):void{
  var b:Button;
  b = e.currentTarget as Button;
  DragManager.doDrag(b, new DragSource(), e);
}


//private

[]Drag and Drop 調査:toオブジェクト

次はtoオブジェクトに実装かけて移動完了とする必要がある。

えと…長いんで、ふくしぅ。

・移動中のfromオブジェクトがtoオブジェクトの上空にいる

・その状態でマウスアップ(クリックの指を外す)が発生する

・fromオブジェクトを受け入れる準備が整ったので「かも〜ん」

ふむり。

次に、イベント系の確認。DragEventをチェック。

http://livedocs.adobe.com/flex/3_jp/langref/mx/events/DragEvent.html

DRAG_DROP、DRAG_ENTER、DRAG_EXITあたりがポイントかしらん。

とりあえずイベントを出すクラス(UIComponentクラス)のイベントを確認。

http://livedocs.adobe.com/flex/3_jp/langref/mx/core/UIComponent.html


dragDrop イベント

ユーザーがドロップターゲット上でマウスを離したとき、ドロップターゲットによって送出されます。


このイベントハンドラは、ドラッグデータをドロップターゲットに追加するために使用します。


ある Tree コントロールから別の Tree コントロールにデータをドラッグするときに、Event.preventDefault() を Tree コントロールの dragDrop イベントのイベントハンドラで呼び出すと、ドロップは行われません。

DragEvent.DRAG_DROP 定数により、イベントオブジェクトの type プロパティ値が dragDrop イベント用に定義されます。


dragEnter イベント

ドラッグ操作時に、コンポーネント上でマウスを移動したとき、コンポーネントによって送出されます。Flash Player で実行しているアプリケーションの場合、コンポーネント上にマウスを移動するたびに何度もこのイベントが送出されます。AIR で実行しているアプリケーションの場合、このイベントは 1 回だけ送出されます。


コンポーネントを有効なドロップターゲットとするには、このイベントのハンドラを定義する必要があります。ハンドラ内では、コンポーネントドラッグを受け付けることができることを示す視覚的なフィードバックをユーザーに提供するために、ドロップターゲットの外観を変更できます。例えば、ドロップターゲットの周囲に境界線を表示したり、ドロップターゲットにフォーカスを移すことができます。


ドラッグを受け入れる場合は、DragManager.acceptDragDrop() メソッドを呼び出す必要があります。acceptDragDrop() を呼び出さないと、他のドラッグイベントがすべて取得されなくなります。


Flash Player では、action プロパティの値は、コピーの実行中も常に DragManager.MOVE です。 これは、Control キーが押され、コピーが通知されたことをコントロールが認識する前に dragEnter イベントが発生するためです。 action プロパティ(dragOver イベントのイベントオブジェクト)には、ドラッグ操作の種類を示した値が含まれています。DragManager.showFeedback() メソッドを呼び出してドラッグアクションの種類を変更することもできます。


dragCompleteイベント

ドラッグ操作が完了したとき(ドラッグデータをドロップターゲットにドロップするか、ドロップを実行せずにドラッグ&ドロップ操作を終了したときのいずれか)、ドラッグイニシエータ(ドラッグしたデータのソースであるコンポーネント)によって送出されます。

このイベントは、ドラッグ&ドロップ操作の最終的なクリーンアップを行うために使用できます。例えば、List コントロールアイテムをあるリストから別のリストにドラッグする場合、List コントロールアイテムがそれ以降必要でなければソースから削除することができます。

ふむり…acceptDragDropあたり不明だし無視してみようかと思ったけど、しっかり釘刺されてる(苦笑


とりあえず実装してみまっしょ。

ついでに、ちょいと遊び入れてます。えと…「括弧の演算子ってインスタンスreferer返すよねぇ普通」に基づく、かなり省略チックな記述です…ってのを先に。

一番わかりやすくてわかりにくいところを一例にとって。


通常

  // 変数宣言して
  var ui_to:UIComponent;
  var ui_from:UIComponent;
  // 型変えて
  ui_to = e.currentTarget as UIComponent;
  ui_from = e.dragInitiator as UIComponent;
  // メソッドcall
  ui_to.addChild(ui_from);

って書くと思うのですが、ぢつはこれ

(e.currentTarget as UIComponent).addChild(e.dragInitiator as UIComponent);

って省略できます。ので、これ使ってます。


で、ソース。


mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="onComplete()">

<!-- ********************************** -->
<mx:Script source="base.as" />


<!-- ********************************** -->
<mx:Panel>
	
<mx:Panel>
  <mx:HBox id="h_from" />
</mx:Panel>

<mx:Panel>
  <mx:HBox id="h_area" />
</mx:Panel>


</mx:Panel>
	
</mx:Application>

Script

//
import flash.events.MouseEvent;

import mx.containers.Panel;
import mx.controls.Button;
import mx.core.DragSource;
import mx.core.UIComponent;
import mx.events.DragEvent;
import mx.managers.DragManager;


private function onComplete():void{
  var btn:Button;
  var pl:Panel;
  for (var i:int = 0; i < 3; i ++) {
    // 置き場所
    pl = new Panel;
    pl.id = "pl_" + i.toString();
    //
    pl.addEventListener(DragEvent.DRAG_ENTER, d_in);
    pl.addEventListener(DragEvent.DRAG_DROP, d_drop);
    //
    h_from.addChild(pl);

    // ボタン
    btn = new Button;
    btn.label = "● " + i.toString();
    btn.id = "btn_" + i.toString();
    //
    btn.addEventListener(MouseEvent.MOUSE_DOWN, m_down);
    //
    h_area.addChild(btn);
  }

}

// マウスダウン
private function m_down(e:MouseEvent):void{
  DragManager.doDrag(e.currentTarget as UIComponent, new DragSource(), e);
}

// 上空におこしやす
private function d_in(e:DragEvent):void {
//trace (e.currentTarget);
//trace (event.dragInitiator);
  DragManager.acceptDragDrop(e.currentTarget as UIComponent);   // ドロップの受け入れ可能
}

// 落下!
private function d_drop(e:DragEvent):void {
//trace (e.currentTarget);
//trace (e.dragInitiator);
  (e.currentTarget as UIComponent).addChild(e.dragInitiator as UIComponent);
}


//private

こげな感じ。


ふむり…なんとかD&D出来るようになったかな。

2009-06-30

[]タイマー的なバー

ほぼmemo。

パッケージみたいなのに出来るんじゃないかと思うんだけど、未確認。

めいん関数 {
  // max時間の設定
  this.time_count_ = 20;
  h1.maximum = this.time_count_;
  h1.value =   this.time_count_;
  h1.minimum = 0;

  // タイマーの設定
  var timer:Timer = new Timer(1000, this.time_count_ );
  timer.addEventListener(TimerEvent.TIMER, dec_timer);
  timer.start();
}

//  減算とタイムアウトの設定
private function dec_timer(ev:TimerEvent)
{
  h1.value = -- this.time_count_;
  if ( 0 == this.time_count_) {
    // タイムアウト!!
    Alert.show("fin!!");
  }
}

//
private var time_count_:int;

そいえば。callbackのところに直接関数書いて、いわゆる「無記名関数」的なことは、可能みたい。

      timer.addEventListener(TimerEvent.TIMER, function(ev:TimerEvent):void {
        text.text = String(i++);
      });

いぢょ ノ

2009-06-29

[]やっぱりないか orz

んと…

・ボタンを、あるタイミングで数含めて動的に生成して(httpでXMLでボタン数とか取得)

・処理関数はfunction一箇所に集中させたい

のですが。

えと…

・callback関数引数が付与できる

or

・イベントを受け取ったwindowインスタンスの名前が拾える

or

・ラムダとかその系が使える

のいずれかがあれば処理できるんだけど…取れないっぽいなぁ orz

traceで、受信したMouseEvent拾ってみたんだけど…

[MouseEvent type="click" bubbles=true cancelable=false eventPhase=2 localX=35 localY=9 stageX=35 stageY=113 relatedObject=null ctrlKey=false altKey=false shiftKey=false delta=0]

XY座標で計算する気にもならないし。

…なんか雑な処理するしかないかなぁ orz


このあたりの、かゆいところがかゆいまま、ってのがFlexが「今ひとつプログラマ向けでない」と感じる理由なんだよなぁ…


[]にぅす

で…偶然めっけ。

Flex 4の新機能トップ10

http://www.infoq.com/jp/articles/top-10-flex4-changes

あたり。…でるんだ。


ただ…新機能見ている限りでは…なんていうか「よりリッチで便利になってより豪華になってるんだけど相変わらず土台が以下略」な印象を受けるのは気のせいでしょうか orz


もう少し…「普通にプログラミングの訓練をした人間が使いやすい」言語になってくれないかなぁ…

[]foreachとかiteratorとか

んと…まずiterator近辺は…多分、ないです。…見落としてるだけかもしれませぬが。

foreachは…二種類あります orz


まず。

いわゆる一般的な手続き型言語でのイメージとしてのforeach(PerlとかPHPとかJava(5.0+)とかC#とかDとかPython(for文だけどforeachと等価だよねぇ)とかVBとかcshとかshシェルとか)は…こんな感じ。

  //
  var awk:Array = ["a", "b", "c", 123];

  for each (var obj in awk) {
  	trace (obj.toString());
  }

まぁ当然といえば当然なのですが、objは「実値のcopy」なので。値を操作してもなんの意味もありません。

  //
  var awk:Array = ["a", "b", "c", 123];

  //
  for each (var obj in awk) {
  	trace (obj.toString());
  	obj = obj + " add";
  }
trace (awk.toString());

ついでに。似たような書式でfor in というのがあるのですが…これは「indexを返す」だけなので。ちょいと物足りない可能性があります。

  //
  var awk:Array = ["a", "b", "c", 123];

  //
  for (var obj in awk) {
  	trace (obj.toString());
  }

次に。「Arrayクラス(…以外にあるのかは不明。少なくともArrayクラスには、程度のニュアンスで捉えてください)にあるforEachというメソッド」という角度が存在します。

で、この子が………callback系の実装をしています。


サンプル1

とある関数 {
  //
  var awk:Array = ["a", "b", "c", 123];

  //
  awk.forEach(ff);
}

private function ff(item:*, index:int, array:Array):void
{
  trace("foreach start");
  trace(item.toString());
  trace(index.toString());
  trace(array.toString());
  trace("foreach end");
}

…少々微妙ではありますが(好みの問題ともいう…で、おいちゃん的にはまったく好みぢゃない)。

とりあえず、処理は可能。


で…疑問。

「foreach内で要素変更は可能か?」言い換えると「refererなのか実値のcopyなのか」。

結論「referer」。


で、サンプル2

とある関数 {
  //
  var awk:Array = ["a", "b", "c", 123];

  //
  awk.forEach(ff);
}

private function ff(item:*, index:int, array:Array):void
{
  //Alert.show("foreach start");
  //Alert.show(item.toString());
  //Alert.show(index.toString());
  //Alert.show(array.toString());
  //Alert.show("foreach end");

  trace("foreach start");
  trace(item.toString());
  trace(index.toString());
  trace(array.toString());
  trace("foreach end");
  array[index] = array[index] + " added";
  trace(item.toString());
  trace(array.toString());
  trace("foreach end");
}

次。callback関数に「クラスインスタンス+メソッド」は可能か?

答え。可能。

package
{
public class foo
{
  public function foo()
  {
  }

  public function f(item:*, index:int, array:Array):void
  {
    trace("foo foreach start");
    trace(item.toString());
    trace(index.toString());
    trace(array.toString());

    trace("foo foreach middle");

    array[index] = array[index] + " added";

    trace(item.toString());
    trace(array.toString());
    trace("foo foreach end");
  }
}
}
とある関数 {
  //
  var awk:Array = ["a", "b", "c", 123];

  //
  var f:foo = new foo;

  awk.forEach(f.f);
}

基本的なloopだってぇのに…まぁ盛りだくさん(苦笑

ただ…おいちゃん的には、iterator実装が欲しかったなぁ、とか思うのですが…どんなもんなんですかね?

2009-06-28

[]キーイベントの取得 追記

なんとびっくり。Window全体…つまり

application.addEventListener(FlexEvent.ENTER , keyHandler);

は、ダメポであることが判明。

コンパイルエラーは出てこないんだけど、取得も出来ないっぽ orz*1

addEventListenerしていいのは、とりあえず現状わかってるので mx:TextInput 。ほかはしらにゃい〜

サンプルコードおいとくわ。


mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="onComplete()">

<!-- *********************************** -->
<mx:Script source="base.as" />

<mx:VBox id="vvv">

<!-- 実験君 -->
<mx:TextInput id="a_txt" enter="onEnter()" text="ほげほげ" />
<mx:Script>
import mx.controls.Alert;

private function onEnter():void {
  trace("test 1");
Alert.show("test 1");
}
</mx:Script>

<!-- *********************************** -->

<mx:TextInput id="ti" width="200" imeMode="JAPANESE_HIRAGANA"  />

<mx:Label id="l1" />
<mx:Label id="l2" />

</mx:VBox>
	
</mx:Application>

base.as

(色々実験してるので、余計なimportは気にすんなw)

// ActionScript file
import flash.media.Sound;
import flash.net.URLRequest;
import flash.utils.Timer;

import mx.controls.Alert;
import mx.controls.Label;
import mx.events.FlexEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

private var external_val:String;

private function onComplete():void{

trace ("onC");
Alert.show( "onC" );

  ti.setFocus(); 
  focusManager.setFocus(ti);

  //
  //application.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
  //ti.addEventListener(KeyboardEvent.KEY_UP, keyHandler2);
  //application.addEventListener(KeyboardEvent.KEY_UP, keyHandler);
  //ti.addEventListener(mx.events.FlexEvent.ENTER , keyHandler2);
  //application.addEventListener(mx.events.FlexEvent.ENTER , keyHandler);
  //ti.addEventListener("enter" , keyHandler2);
  //
  ti.addEventListener(FlexEvent.ENTER , keyHandler2);
  application.addEventListener(FlexEvent.ENTER , keyHandler);

}

//private function keyHandler(event:KeyboardEvent):void {
private function keyHandler(e:FlexEvent):void {
  //Alert.show( event.keyCode + "/" + event.charCode );
  //trace( event.keyCode + "/" + event.charCode );
  trace( "event 1");
}

//private function keyHandler2(event:KeyboardEvent):void {
private function keyHandler2(e:FlexEvent):void {
  //Alert.show( "2:" + event.keyCode + "/" + event.charCode );
  //trace( "2:" + event.keyCode + "/" + event.charCode );
  Alert.show(" event 2" );
  trace( "event 2");
  trace ( e );
}

とりあえず。部品系のコンポーネントぢゃないと取得できないんだとすると…「どのコントロールなら行けるのか」、そのうち調べ尽くさないと、かも。

*1:なんかミスってたら誰か突っ込んで〜

2009-06-26

[]キーイベントの取得

発端は「Enterキーを押したら、あるボタンをClickしたのと同じ効果が欲しい」というご要望。

まぁよくありげなお話しです。


基本的には

application.addEventListener(KeyboardEvent.KEY_UP, keyHandler);

という感じで、KEY_UPのキーボードイベントにcallback関数を紐付けて、あとはそちらで

public function keyHandler(event:KeyboardEvent):void {
  if (13 == event.keyCode) {
    var ooo:MouseEvent = new MouseEvent(MouseEvent.CLICK);
    ボタンのインスタンス.dispatchEvent(ooo);
  }
}

という感じでEnterをClickイベントに紐付けて…ドはまり orz


えとですね。

普通。日本語入力システム(IMEとかそゆやつ)のイベントは、その後ろの(より親に近い)windowのイベントには流れないものなのですが。

が。

が。

Flashはそゆことないらしいのですが…Flexは、日本語入力システム中にも、クリアにキーイベントを取得します。

つまり。


1)「わたし」と入力

2)スペースキーを数回(多分1回)おして日本語変換候補

3)Enterキーをおして日本語変換確定

4)「は」と入力

5)Enterキーをおして日本語変換確定

6)Enterキーを押して「解答ボタンをクリック」と等価の効果を期待


という事をやりたい時に。6のEnterのkeyイベントを取得…するまえに、3と5のイベントを取得できてしまうです orz

しか〜も。

  trace ( e );

とかでイベントの差違をみるも…3,5と6の間には、な〜〜〜んの差違もございません orz


で、結論。

こう、実装します(ActionScriptベース。今度きちんと書くけど。ロジックmxmlに書くのやめようよって、おいちゃんは思ってるので)。

<mx:TextInput id="ti" width="200" imeMode="JAPANESE_HIRAGANA"  />

として。

  ti.addEventListener(FlexEvent.ENTER , keyHandler2);

あんど

private function keyHandler2(e:FlexEvent):void {
  Alert.show(" event 2" );
  trace( "event 2");
  trace ( e );
}

ってな感じ。一応おいちゃん的に非推奨だけど

<mx:TextInput id="t2" enter="onEnter()" text="ほげほげ" />
<mx:Script><![CDATA[
import mx.controls.Alert;

private function onEnter():void {
  trace("test 1");
Alert.show("test 1");
}
]]></mx:Script>

って書式でも動きまふ。


Flex、癖強すぎ orz


&余談。


んと…上述、一発目書いた時。意味不明なエラーが出続けてました。

OS再起動した「だけ」であっさり動いたあたり…やっぱりこのIDE、かなり駄目な予感 orz

挙動が不安な時は。全部一式再起動すると、もしかしたら動く…かもしれません。

# エラーの場所指し示さないのにエラー出続けてたしなぁ orz


PS

http://d.hatena.ne.jp/gallu/20090628/p2

に追記があるのでよろしければ読んでくんなまっしょ。