ログイン
ユーザ名:

パスワード:


パスワード紛失

新規登録
メインメニュー
フォーラム一覧   -   トピック一覧
   ActionScript 3.0
     addEventListener メソッドについて
投稿するにはまず登録を

スレッド表示 | 新しいものから 前のトピック | 次のトピック | 下へ
投稿者 トピック
muchag
投稿日時: 2010-7-14 2:54
やや お馴染みさん
登録日: 2010-7-14
居住地:
投稿: 7
addEventListener メソッドについて
はじめまして、muchag と申します。

Flash Builder 4 で作業をしていますが
ActionScript 3.0 についての質問なので、こちらへ投稿しました。

もし板違いであれば、その旨教えてください。


さて、問題点です。

private var mySite:Object;

private function onResult(event:ResultEvent, obj:Object=null):void{

	for (var i:Number = 0; i < event.result.length; i++) {

		mySite = event.result[i] as Object;
		var myLinkButton:LinkButton = new LinkButton();
		myLinkButton.id = "Site" + i;
		myLinkButton.label = mySite.title;

		myLinkButton.addEventListener(MouseEvent.CLICK, function():void{
 			navigateToURL(new URLRequest(mySite.link), "_blank");
		});

		myGroup.addElement(myLinkButton);
	}
}

※myGroup は、ステージ上に設置済みです。


上記コードにて、各サイトへのリンクボタンを生成しています。

Object型のデータから1サイトずつ情報を取り出して
ボタンの labelプロパティ と クリックイベントにそれぞれデータを代入しています。

ボタンの labelプロパティ については、希望通り各サイトのタイトルを表示させることができました。

しかしながら、リンクは全ボタン同じURLになってしまうのです。
(同じURLとは、最後のデータのURLになります)

検索していて、ループは for each を使っておられましたが
ほぼ同じコードを見つけたので、そちらで試してみましたが同じ結果でした。

リンク以外は全て希望通りなので、addEventListener の部分が問題だと思うのですが、いくら検索しても解決できませんでした。

原因なり解決法なり、お気づきの点があればぜひとも教えてください。

よろしくお願いします。
ksk8787
投稿日時: 2010-7-14 9:23
ご主人様
登録日: 2010-5-24
居住地: 井の中
投稿: 63
Re: addEventListener メソッドについて
サンプルaddEventListenerで設定した関数は、「クリックした時」に実行されます。

その時mySiteの中身はForループの最後の値が入っているからじゃないですかね?


こんなのはどうでしょう?
myButtonのdataにリンク先を代入しておいて、
イベントハンドラではターゲットからセットしておいたリンク先を使用

private var mySite:Object;

private function onResult(event:ResultEvent, obj:Object=null):void{

	for (var i:Number = 0; i < event.result.length; i++) {

		mySite = event.result[i] as Object;
		var myLinkButton:LinkButton = new LinkButton();
		myLinkButton.id = "Site" + i;
		myLinkButton.label = mySite.title;
		myLinkButton.data = mySite.link;

		myLinkButton.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void{
 			navigateToURL(new URLRequest(e.currentTarget.data), "_blank");
		});

		myGroup.addElement(myLinkButton);
	}
}
sakuzo
投稿日時: 2010-7-14 9:54
やや 常連さん
登録日: 2010-3-2
居住地: 埼玉県政令指定都市
投稿: 21
Re: addEventListener メソッドについて
ksk8787さんが1つの解を投稿されているので、ヒント的なコメントを残しておきます。

addEventListener()で使用されている無名関数を外出しすると以下のようになります。
---------------------
private var mySite:Object;

private function onResult(event:ResultEvent, obj:Object=null):void{
 for (var i:Number = 0; i < event.result.length; i++) {
  mySite = event.result[i] as Object;
  var myLinkButton:LinkButton = new LinkButton();
  myLinkButton.id = "Site" + i;
  myLinkButton.label = mySite.title;

  myLinkButton.addEventListener(MouseEvent.CLICK, hogehoge); //←実行すべき関数を外出しした
   myGroup.addElement(myLinkButton);
  }
}

//↓↓↓ 外出しした関数
private function hogehoge() : void
{
 navigateToURL(new URLRequest(mySite.link), "_blank");
}
---------------------

リンクボタンをクリックする度にhogehoge()を呼ぶわけですが、
その時の mySite オブジェクトに何が入っているかを想像して頂ければ意図しない動きになることが分ると思います。

処理を追えば分りますが、onResult() の実行後は mySite にはループ最後のリンク情報が入っていることになります。
ですので、どのリンクボタンをクリックしてもループ最後のリンク情報を参照してしまうことになります。

Javascript等でもうっかり陥ってしまうミスで、
「クロージャ」「無名関数」あたりで検索すると色々出てきます。

kacchan6
投稿日時: 2010-7-14 10:24
ご主人様
登録日: 2009-10-15
居住地:
投稿: 167
Re: addEventListener メソッドについて
実行効率からするとあまりオススメではない方法になりますが、
構造を大きく変え難い時向けの解決方法です。

myLinkButton.addEventListener(MouseEvent.CLICK, (function(mySite:Object):Function{
	return function(e:Event):void{
		navigateToURL(new URLRequest(mySite.link), "_blank");
	};
})(mySite));

関数を返す関数をインラインで実行しますが、
ループのある方の関数のスコープの変数を、
「関数を返す関数」のスコープに変えることで、
ループ毎の変数の状態を保持します。

ただし、関数オブジェクトが都度作られますので、
クリティカルな場所ではおすすめしません。
muchag
投稿日時: 2010-7-14 15:16
やや お馴染みさん
登録日: 2010-7-14
居住地:
投稿: 7
Re: addEventListener メソッドについて
ksk8787 さん 回答をありがとうございます。

引用:
サンプルaddEventListenerで設定した関数は、「クリックした時」に実行されます。
その時mySiteの中身はForループの最後の値が入っているからじゃないですかね?

やっぱりそうでしたか。

漠然とはそのように思っていたのですが、
具体的な方法がわからず教えを請いました。

引用:
myButtonのdataにリンク先を代入しておいて、 イベントハンドラではターゲットからセットしておいたリンク先を使用

これです! 正にこの方法を探していました。

以前VBを触っていた頃には、
Button に label プロパティ(captionだったかも)以外に value プロパティというのがあって、
上記のような使い方ができたのです。

実はこのために LinkButton の数だけ Label を配置して visible = false にしちゃおうかなんて思ってました。 (´ヘ`;)

教えていただいた方法で、無事に意図通りの動作をしました。
ありがとうございました。


---
余談になりますが
上記コードは、元々は Label で作成していまして
その後 Button そして LinkButton と変遷しました。

Label で作っていたときに、上記 data プロパティのようなものを探して
Adobe® Flex® 4 リファレンスガイド を見ていたのですが、
該当するものを見つけられませんでした。

今 Button について探してみましたが、やはり見つけられません。

Label や Button で上記機能を実現しようとしたら、
(現在の私の能力では及びませんが)
クラスか何かで独自機能を付加するしかないんでしょうかね。

LinkButton にそういう機能があるんだから、
敢えて Label や Button でやろうとするな、ということなのかなぁ。


---
2010-07-14 16:27 追記

Adobe® Flex® 4 リファレンスガイド を見ていたら
mx.controls の Label や Button には data プロパティがありました。

data プロパティがないのは、spark.components の Label や Button でした。

失礼しました。
muchag
投稿日時: 2010-7-14 15:30
やや お馴染みさん
登録日: 2010-7-14
居住地:
投稿: 7
Re: addEventListener メソッドについて
sakuzo さん、回答をありがとうございます。

引用:
リンクボタンをクリックする度にhogehoge()を呼ぶわけですが、
その時の mySite オブジェクトに何が入っているかを想像して頂ければ意図しない動きになることが分ると思います。

そうですね、今回の件でハッキリとそれがわかりました。

値は「埋め込み式」のイメージが強く
addEventListener メソッドのように、クリック時に初めて変数を参照する
という処理がピンときていませんでした。

「クロージャ」については、以前読んだことがありますが
小規模なものしか作っていない私には「どの場面で必要となるのか」
これまたピンときていません。

今回の件で「クロージャ」をどう利用したらいいのかわかりませんが
追々、勉強していきたいと思います。

おかげさまで、また一歩理解が深まりました。
ありがとうございました。
muchag
投稿日時: 2010-7-14 15:38
やや お馴染みさん
登録日: 2010-7-14
居住地:
投稿: 7
Re: addEventListener メソッドについて
kacchan6 さん、回答をありがとうございます。

引用:
関数を返す関数をインラインで実行しますが、
ループのある方の関数のスコープの変数を、
「関数を返す関数」のスコープに変えることで、
ループ毎の変数の状態を保持します。

なるほど、この手法はこういうところで使うんですね。

以前見たときはサッパリ理解ができませんでしたが
この具体例で少しわかった気がします。

おかげさまで、枠が1つ広がりました。
ありがとうございました。
スレッド表示 | 新しいものから 前のトピック | 次のトピック | トップ

投稿するにはまず登録を