フォーラム一覧   -   トピック一覧
   超ビギナー
     DataGridに配置したButtonを制御したいのですが
投稿するにはまず登録を

スレッド表示 | 新しいものから 前のトピック | 次のトピック | 下へ
投稿者 トピック
clecle
投稿日時: 2008-8-27 0:25
やや お馴染みさん
登録日: 2008-8-26
居住地: 仙台付近。。。
投稿: 6
DataGridに配置したButtonを制御したいのですが
初めて質問させていただきます。clecleです。

Flexを始めてひと月未満の超ビギナーです。

以下の「itemRendererに配置したbuttonにセットフォーカスしたいのですが」のトピックスから、
ついでに(?)ボタンの無効化や非表示なども制御したいなあと思い立ちこつこつといじっていたのですが
行き詰ってしまいました。

http://www.fxug.net/modules/xhnewbb/viewtopic.php?viewmode=thread&topic_id=2141&forum=16&post_id=8909#8909

やりたいことは別カラムの値から、
 1.ボタンを無効化したい。
 2.ボタンを非表示にしたい。
 3.無効化・非表示にしたgridにはフォーカスが当たらない
  ようにしたい(Tab移動できないようにしたい)。
の3つです。

1は実現できたのですが、2は1と同じように作ってみても初期表示では非表示にできず
Tabでフォーカスを移動したりしてると非表示になります。
動作がおかしいです。原因が分からず参考になりそうなページも見つけられず固まっております。
3にいたっては手の付け所が分からなかったり・・・orz

以下ためしに作ってみたソースです。(参考にもならないと思いますが・・・)
『testGridButton.mxml』
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
	xmlns:as="*"
	backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]">

	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;

			[Bindable]
			public var testdata:Array = [
				{col1:"Test1", col2:'0'},
				{col1:"Test2", col2:'1'},
				{col1:"Test3", col2:'0'}
			];

			// cleckイベント
			public function clkSelect(e:Event):void {
				Alert.show("TEST!!");
			}
			
		]]>
	</mx:Script>

	<mx:DataGrid x="10" y="10" width="300" height="150"
		id="dg" editable="true" dataProvider="{testdata}">
		<mx:columns>
			<mx:DataGridColumn headerText="列 1" dataField="col1" editable="false"/>
			<mx:DataGridColumn headerText="列 2" dataField="col2" editable="false"/>
			<mx:DataGridColumn headerText="列 3" dataField="col3" 
				editable="true" 
				rendererIsEditor="true"
				editorUsesEnterKey="true">
				<mx:itemRenderer>
					<mx:Component>
						<as:GridButton label="無効" right="0" 
							enabled="{data.col2==0}"
							click="parentDocument.clkSelect(event)"/>
					</mx:Component>
				</mx:itemRenderer>
			</mx:DataGridColumn>
			<mx:DataGridColumn headerText="列 3" dataField="col3" 
				editable="true" 
				rendererIsEditor="true"
				editorUsesEnterKey="true">
				<mx:itemRenderer>
					<mx:Component>
						<as:GridButton label="非表示" right="0" 
							visible="{data.col2==0}"
							enabled="{data.col2==0}"
							click="parentDocument.clkSelect(event)"/>
					</mx:Component>
				</mx:itemRenderer>
			</mx:DataGridColumn>
		</mx:columns>
	</mx:DataGrid>
	
</mx:Application>


『GridButton.as』
package
{
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	
	import mx.controls.Button;

	public class GridButton extends Button {
		// textプロパティ
		private var _text:String = null;
		private var isKeyDownPhase:Boolean = false;

		/**
		 * コンストラクタ
		 */
		public function GridButton(){
			super();
		}
		
		// textプロパティセッタ
		public function set text(value:String):void {
			_text = value;
		}
		
		// textプロパティゲッタ
		public function get text():String {
			return _text;
		}
		
		/**
		 * keyDownHandler
		 * @param event KeyboardEventオブジェクト
		 */
		override protected function keyDownHandler(event:KeyboardEvent):void {
			if (event.keyCode == Keyboard.ENTER) {
				isKeyDownPhase = true;
			} else {
				super.keyDownHandler(event);
			}
		}

		/**
		 * keyUpHandler
		 * @param event KeyboardEventオブジェクト
		 */
		override protected function keyUpHandler(event:KeyboardEvent):void {
			if (event.keyCode == Keyboard.ENTER && isKeyDownPhase) {
				var mouseEvent:MouseEvent = 
					new MouseEvent(MouseEvent.CLICK, true, false, NaN, NaN, null,
						event.ctrlKey, event.altKey, event.shiftKey, false, 0);
				this.dispatchEvent(mouseEvent);
				isKeyDownPhase = false;
			} else {
				super.keyUpHandler(event);
			}
		}
	}
}


3はもしかした構造的に無理なのかなともうすうす思っているのですが、
無効化ができたのに非表示化はなぜできないのでしょうか。

なにか参考になるヘルプ等知っている方がいましたらアドバイス等いただけないでしょうか。
よろしくお願いいたします。
goki
投稿日時: 2008-8-28 10:35
ご主人様
登録日: 2007-8-27
居住地: おかのよこはま
投稿: 735
Re: DataGridに配置したButtonを制御したいのですが
これが参考になりませんか?
服部さんのブログ
itemRenderer パート4 : ステート & トランジション
http://blog.banana-systems.com/archives/879007.html
clecle
投稿日時: 2008-8-29 0:31
やや お馴染みさん
登録日: 2008-8-26
居住地: 仙台付近。。。
投稿: 6
Re: DataGridに配置したButtonを制御したいのですが
gokiさんありがとうございます。

『バナナ研究所』・・・Flexを連想できませんねw

教えていただいた記事を参考にGridButton.as内でset dataを
オーバーライドしてみたのですが
ルートタグ直下に配置したStateが見つかりませんというエラーがorz

以下エラー内容
ArgumentError: Undefined state 'NoVisible'.
	at mx.core::UIComponent/getState()
	at mx.core::UIComponent/findCommonBaseState()
・・・

当然だよなと思いつつ初歩的な質問で申し訳ないのですが、
GridButton.as内からどのようにしたらtestGridButton.mxmlの
ルートタグ直下に配置したStateを参照できるようになるのでしょうか。

ためしにset data内でvisibleを直接書き換えてみたのですが
動作は相変わらずでした(トホホ)

服部さんのブログの記事は2の非表示に関するものですよね?
3のタブ制御はitemRendererをカスタムすればできるのでしょうか。
カスタムitemRendererにmx:Componentを使用してGridButton.asを配置しようとしたら
使用できませんとコンパイルエラーがーーーT_T
wolf
投稿日時: 2008-8-29 22:43
ご主人様
登録日: 2007-1-26
居住地: 千葉
投稿: 199
Re: DataGridに配置したButtonを制御したいのですが
hattoriさんは、アイテムレンダラーそのものをMXMLで書いているみたいですよ。つまり、GridButton.asではなくGridButton.mxmlを書いています。
clecle
投稿日時: 2008-8-31 23:33
やや お馴染みさん
登録日: 2008-8-26
居住地: 仙台付近。。。
投稿: 6
Re: DataGridに配置したButtonを制御したいのですが
wolfさんありがとうございます。

返信が遅くなり申し訳ありませんでした。

『ActionScript のみでも作成可能です』とhattoriさんのブログには書かれているのですが、
ActionScriptのみで作成するのはハードルが高いのでしょうか。
まあ、ActionScriptだけで作らなければいけない理由はないのですが。。。

>hattoriさんは、アイテムレンダラーそのものをMXMLで書いているみたいですよ。つまり、GridButton.asではなくGridButton.mxmlを書いています。

あーーー。
『ルートタグ直下』というのはitemRenderer内のということなのですね。

うーん、なにか分かったような気がしますです。はい。
もうちょっと自分で考えてコーディングしなおしてみます。

何度も何度もすみません
goki
投稿日時: 2008-9-1 11:23
ご主人様
登録日: 2007-8-27
居住地: おかのよこはま
投稿: 735
Re: DataGridに配置したButtonを制御したいのですが
GridButton.asでも、

		public override function initialize():void {
			var invisible:State = new State();
			var property0:SetProperty = new SetProperty(this, "visible", false);
			invisible.name = "invisible";
			invisible.overrides.push(property0);
			var visible:State = new State();
			var property1:SetProperty = new SetProperty(this, "visible", true);
			visible.name = "visible";
			visible.overrides.push(property1);
			states.push(visible);
			states.push(invisible);
			super.initialize();
		}

こんな感じで書けばいいですよ。

ただ、今回の場合いじるプロパティが2つしかないので、
Stateを使う必要はないかも。

override public function set data( value:Object ):void {
    super.data = value;
    if(data) {
        if(data.col2 == 0) {
            currentState = "visible";
        } else {
            currentState = "invisible";
        }
    }
}

currentState の部分を

    visible = true;
    enabled = true;

などと書いても大差ないです。

で、このとおり実装した場合今度は
・visible=falseでもFocusInしたときにコンポーネントがvisible="true"になってしまう。
問題がある模様
clecle
投稿日時: 2008-9-2 1:40
やや お馴染みさん
登録日: 2008-8-26
居住地: 仙台付近。。。
投稿: 6
Re: DataGridに配置したButtonを制御したいのですが
gokiさん、ソースまで添付していただいてありがとうございます。

大変参考になります

>で、このとおり実装した場合今度は
>・visible=falseでもFocusInしたときにコンポーネントが>visible="true"になってしまう。
>問題がある模様

あれ?自分の環境ではtab移動でフォーカス自体が当たらなくなったのですが
(ちなみにマウスでも当たりません)
FocusInできますか?

ただ、バインドしているデータを変更してrefresh()でビューに反映したりすると
visibleがtrueに変わってしまいます。

たぶんFocusInの同じタイミングだと思いますが、hattoriさんのブログにも書かれている
『itemRenderer は再利用されます』が原因でしょうか。

itemRendererを再利用させないようにitemRenderer内のコンポーネントを
きれいに(removeやパージ?Flexにあるのか分かりませんが。。。)
させることはできないのでしょうか。

質問君で本当に申し訳ありませんがよろしくお願いいたします。
goki
投稿日時: 2008-9-2 14:01
ご主人様
登録日: 2007-8-27
居住地: おかのよこはま
投稿: 735
Re: DataGridに配置したButtonを制御したいのですが
どう実装しました?

Flexのバージョンはいくつですか?
(私の環境でビルドするとvisibleがtrueになったりfalseになったりします。enable=falseにしてもフォーカスインができてしまいます。)
確認したバージョンは以下のとおり
Flex SDK 2.0.1 HotFix 3/3.0.0/3.2.0.2670
FlashPlayer 9.0.124.0
実体+ソースは下のURLにあります。
http://solidate.s10.xrea.com/Flex/ClecleSample/ClecleSample.html
(ソースは右クリックして「ソースの表示」)

ただ、バインドしているデータを変更してrefresh()でビューに反映したりすると
visibleがtrueに変わってしまいます。


これは
『itemRenderer は再利用されます』

が原因です。
itemRendererのdataChangeイベントで似たような制御を行う必要がありそうです。
clecle
投稿日時: 2008-9-3 0:24
やや お馴染みさん
登録日: 2008-8-26
居住地: 仙台付近。。。
投稿: 6
Re: DataGridに配置したButtonを制御したいのですが
>Flexのバージョンはいくつですか?

環境情報もお伝えせずに失礼しましたm(_ _)m

Flex Builder 3でテストしています。
SDKのversionの確認の仕方がよくわからなかったのですが、ヘルプには
『Flex Builder 3 Japanese Standalone
Version : 3.0.205647』(←これがSDKのversionとイコールなのでしょうか?)
と書かれています。

FlashPlayerはadobeの「Flash Player バージョン確認テスト(下記参照)」で確認したところ『9.0.124.0』でした。

http://www.adobe.com/jp/support/flashplayer/


>どう実装しました?

gokiさんから提示していただいたソースをGridButton.asに組み込んだだけでたいした違いはないのですが。。。

ただ一つ違うのはdatagridをAdvancedDataGridに変更したくらいです。
(なぜ変更したかはhidariさんのスレに『datagrid(またはAdvancedDataGrid)内に』と
書かれていたので深い意味は何もありませんよ。
ただの思い付き、というか色々試していたのでその過程で。。。)

(ちなみにマウスでも当たりません)

と以前書いたのですがそれは間違いでした。すみません。
対象行にはちゃんとフォーカスが当たります。

tab制御では当たらずに飛ばされますのでvisibleが書き換わることはありませんね。
FocusInできないのだから当然といえば当然ですが。。。

以下、テストソースです。
『GridButton.as』
package
{
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	
	import mx.controls.Button;
	import mx.states.State;
	import mx.states.SetProperty;

	public class GridButton extends Button {
		// textプロパティ
		private var _text:String = null;
		private var isKeyDownPhase:Boolean = false;

		/**
		 * コンストラクタ
		 */
		public function GridButton(){
			super();
		}
		
		// textプロパティセッタ
		public function set text(value:String):void {
			_text = value;
		}
		
		// textプロパティゲッタ
		public function get text():String {
			return _text;
		}
		
		public override function initialize():void {
			// stateの生成
			var invisible:State = new State();
			var property0:SetProperty = new SetProperty(this, "visible", false);
			invisible.name = "invisible";
			invisible.overrides.push(property0);
			
			// stateの生成
			var visible:State = new State();
			var property1:SetProperty = new SetProperty(this, "visible", true);
			visible.name = "visible";
			visible.overrides.push(property1);
			
			// 生成したstateをセット
			states.push(visible);
			states.push(invisible);
			super.initialize();
		}
		
		override public function set data( value:Object ) : void
		{
			super.data = value;
			if( data ) {
		        if(data.col2 == 0) {
		            currentState = "visible";
		        } else {
		            currentState = "invisible";
		        }
			}
		}
		
		/**
		 * keyDownHandler
		 * @param event KeyboardEventオブジェクト
		 */
		override protected function keyDownHandler(event:KeyboardEvent):void {
			if (event.keyCode == Keyboard.ENTER) {
				isKeyDownPhase = true;
			} else {
				super.keyDownHandler(event);
			}
		}

		/**
		 * keyUpHandler
		 * @param event KeyboardEventオブジェクト
		 */
		override protected function keyUpHandler(event:KeyboardEvent):void {
			if (event.keyCode == Keyboard.ENTER && isKeyDownPhase) {
				var mouseEvent:MouseEvent = 
					new MouseEvent(MouseEvent.CLICK, true, false, NaN, NaN, null,
						event.ctrlKey, event.altKey, event.shiftKey, false, 0);
				this.dispatchEvent(mouseEvent);
				isKeyDownPhase = false;
			} else {
				super.keyUpHandler(event);
			}
		}
	}
}


『testGridButton.mxml』
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" 
	xmlns:as="*"
	backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]">

	<mx:Script>
		<![CDATA[
			import mx.controls.Alert;

			[Bindable]
			public var testdata:Array = [
				{col1:"Test1", col2:'0'},
				{col1:"Test2", col2:'0'},
				{col1:"Test3", col2:'1'},
				{col1:"Test4", col2:'0'},
				{col1:"Test5", col2:'0'},
				{col1:"Test6", col2:'1'},
				{col1:"Test7", col2:'0'},
				{col1:"Test8", col2:'0'},
				{col1:"Test9", col2:'1'},
				{col1:"Test10", col2:'0'},
				{col1:"Test11", col2:'0'},
				{col1:"Test12", col2:'1'},
				{col1:"Test13", col2:'0'}
			];

			// cleckイベント
			public function clkSelect(e:Event):void {
				Alert.show("TEST!!");
			}
			
		]]>
	</mx:Script>

	<mx:AdvancedDataGrid x="10" y="10" width="300" height="600"
		id="dg" 
		editable="true" 
		designViewDataType="flat" 
		displayItemsExpanded="true"
		sortableColumns="false"
		sortExpertMode="true"
		draggableColumns="false"
		resizableColumns="false"
		dataProvider="{testdata}">
		<mx:columns>
			<mx:AdvancedDataGridColumn headerText="列 1" dataField="col1" editable="false"/>
			<mx:AdvancedDataGridColumn headerText="列 2" dataField="col2" editable="false"/>
			<mx:AdvancedDataGridColumn headerText="列 3" dataField="col3" 
				editable="true" 
				rendererIsEditor="true"
				editorUsesEnterKey="true">
				<mx:itemRenderer>
					<mx:Component id="compCol2">
						<as:GridButton label="非表示" right="0" 
							enabled="{data.col2=='0'}"
							click="parentDocument.clkSelect(event)"/>
					</mx:Component>
				</mx:itemRenderer>
			</mx:AdvancedDataGridColumn>
		</mx:columns>
	</mx:AdvancedDataGrid>
	
</mx:Application>


gokiさんのソースを見ていて気づいたのですが、バインドしているデータ件数が増えて
datagridにスクロールが表示されるとitemRendererの再利用問題(勝手に命名w)が出てきますね。

>itemRendererのdataChangeイベントで似たような制御を行う必要がありそうです。

itemRendererの内側に参照できるのでしょうか。
「Rendererの内側と外側では別世界」みたいな記述も見た記憶があるのですがインスタンスの特定はどのように記述すればいいのでしょうか。
goki
投稿日時: 2008-9-3 12:18
ご主人様
登録日: 2007-8-27
居住地: おかのよこはま
投稿: 735
Re: DataGridに配置したButtonを制御したいのですが
引用:
『Version : 3.0.205647』(←これがSDKのversionとイコールなのでしょうか?)

違います。Flex SDKのバージョンはAdobe Open Sourceからダウンロードして使えるように設定していない限り、「Flex 3」(3.0.0)です。
プロジェクトのプロパティーを開いて、「Flexコンパイラ」で確認できます。

引用:
ただ一つ違うのはdatagridをAdvancedDataGridに変更したくらいです。


このキーワード結構重要です…。AdvancedDataGridはProfessionalでないと使えないし(正確にはビルドはできるが透かしが出るんでしたっけ)。

また、
displayItemsExpanded="true"

も追加してますよね。

AdvancedDataGrid/AdvancedDataGridColumn/AdvancedDataGridItemRendererはDataGrid/DataGridColumn/DataGridItemRendererを継承したコンポーネントではないので、
・AdvancedDataGridだけで行われた機能改善
・DataGridではつぶされているバグがAdvancedDataGridではつぶされていない
といったことがあります。(今回はおそらく前者)

引用:
「Rendererの内側と外側では別世界」みたいな記述も見た記憶があるのですがインスタンスの特定はどのように記述すればいいのでしょうか。

というスタンスで挑むのは非常に危険だと私は思います。
(1) 2 »
スレッド表示 | 新しいものから 前のトピック | 次のトピック | トップ

投稿するにはまず登録を