AdvancedDataGridにコンテキストメニューを開いた位置を取得したいときがあるのだが、なかなかうまい方法がなかった。
itemRollOverが発生した時に行と列を保存しておくという手法がちらほら書かれているが、試してみたところうまく機能しない場合があった。
稀にロールオーバーのイベントが飛んで来ずに、マウスのポイントしている位置とコンテキストメニューを開いた時に取得できる位置がずれてしまう。
そこで別の方法を探すことにしたのだが、なかなか良さそうな方法を見つけた。
AdavancedDataGridはデフォルトの状態で、マウスがポイントしている行やヘッダの背景色を変更する。
この背景色を変える処理を参考にして、ポイントしている位置を取得すればいい。
AdvancedDataGridはソースコードが公開されているので、mouseOverHandler()の実装を参考にして
うまくマウスのポイント位置から行と列を取得することができた。
この下記のサンプルだとコンテキストメニューのアイテムをクリックしたときに保存された行と列の情報にアクセスしているが
コンテキストメニューを開いた瞬間のマウスポイント位置のデータをうまく取得できる。
どうやら、コンテキストメニューを開いたあとはAdvancedDataGridのmouseOverHandler()が呼び出されないらしい。
もしメニューが開いたあともmouseOverHandler()が呼ばれる場合はContextMenuEvent.MENU_SELECTの発生時に
データを他に逃がす処理などを入れなければならなかったが、その必要はなくシンプルに実装できた。
<?xml version="1.0" encoding="utf-8"?>
<mx:AdvancedDataGrid xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="advanceddatagrid1_creationCompleteHandler(event)">
<fx:Declarations>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.events.FlexEvent;
[Bindable]
public var mouseOveredHeaderColumn:AdvancedDataGridColumn;
[Bindable]
public var mouseOveredColumn:AdvancedDataGridColumn;
[Bindable]
public var mouseOveredRow:int = -1;
override protected function mouseOverHandler(event:MouseEvent):void {
mouseOveredHeaderColumn = null;
mouseOveredColumn = null;
mouseOveredRow = -1;
var item:IListItemRenderer = mouseEventToItemRenderer(event);
var dropInItem:IDropInListItemRenderer;
if (item) {
dropInItem = item as IDropInListItemRenderer;
}
var colNum:int;
if (dropInItem && dropInItem.listData) {
colNum = dropInItem.listData.columnIndex;
}
if (dropInItem
&& isHeaderItemRenderer(item)
&& sortableColumns
&& colNum != -1
&& columns[colNum].sortable
&& Object(item).hasOwnProperty("mouseEventToHeaderPart") )
{
var headerPart:String = Object(item).mouseEventToHeaderPart(event);
mouseOveredHeaderColumn = item.data as AdvancedDataGridColumn;
}
else if ( item != null && !isHeaderItemRenderer(item) )
{
mouseOveredColumn = this.columns[colNum] as AdvancedDataGridColumn;
var pt:Point = itemRendererToIndices(item);
mouseOveredRow = pt.y;
}
super.mouseOverHandler(event);
}
protected function advanceddatagrid1_creationCompleteHandler(event:FlexEvent):void
{
var item:ContextMenuItem = new ContextMenuItem("くりっくみー");
item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, clickListener);
var cmenu:ContextMenu = new ContextMenu();
cmenu.customItems.push(item);
this.contextMenu = cmenu;
}
protected function clickListener(event:ContextMenuEvent):void {
var str:String = "";
str += "row:" + mouseOveredRow + " ";
if ( mouseOveredColumn ) {
str += "column:" + mouseOveredColumn.headerText;
}
if ( mouseOveredHeaderColumn ) {
str += "header:" + mouseOveredHeaderColumn.headerText;
}
Alert.show(str);
}
]]>
</fx:Script>
</mx:AdvancedDataGrid>