我们的系统需要实现这么一个功能,即以矩阵的形式显示用户权限分配的情况。最终的显示效果如下:
这个功能实现起来不是那么容易。当然,要动态添加列很简单:只要知道所有要添加的列,生成一堆DataGridColumn再放到一个数组里就好了。但问题是,DataGridColumn只能简单的指定一个itemRenderer,那么这个itemRenderer如何知道自己应该属于哪一列呢?
答案在于itemRenderer这个属性的类型。
我们的系统需要实现这么一个功能,即以矩阵的形式显示用户权限分配的情况。最终的显示效果如下:
这个功能实现起来不是那么容易。当然,要为DataGrid动态添加列很简单:只要知道所有要添加的列,生成一堆DataGridColumn再放到一个数组里就好了。但问题是,DataGridColumn只能简单的指定一个itemRenderer,那么这个itemRenderer如何知道自己应该属于哪一列呢?
答案在于itemRenderer这个属性的类型。它不是一个简单的数据,而是一个要求实现了IFactory接口的对象。Flex中实现IFactory接口的基本类型是ClassFactory,ClassFactory有一个特殊属性properties,只要设置了它,就会在创建实例的时候自动附加到新实例中对应的属性值。
明白了这一点,问题就迎刃而解了。完整的实现代码如下:
Code
package cps.comps
{
import cps.vo.*;
import mx.collections.*;
import mx.controls.*;
import mx.controls.dataGridClasses.*;
import mx.core.ClassFactory;
/**
* 显示检查框的网格
*/
public class MatrixGrid extends DataGrid
{
public function MatrixGrid()
{
lockedColumnCount = 1;
}
/**
* 设置dataProvider时,根据数据内容手动生成对应的列
*/
public override function set dataProvider(value: Object): void
{
var cols: Array = [];
var labelCol: DataGridColumn = new DataGridColumn();
labelCol.dataField = 'label';
labelCol.headerText = '';
cols.push(labelCol);
for each (var col: Object in value.columns)
cols.push(createColumn(col));
this.columns = cols;
super.dataProvider = parse(value);
}
/**
* 根据数据创建列
*/
private function createColumn(colData: Object): DataGridColumn
{
var col: DataGridColumn = new DataGridColumn();
col.headerText = colData.name;
col.dataField = String(colData.id);
var cf: ClassFactory = new ClassFactory(MatrixItemRenderer);
cf.properties = { dataField: col.dataField };
col.itemRenderer = cf;
return col;
}
/**
* 将界面数据转换为向服务器请求的数据格式
*/
public function getResult(): Array
{
var result: Array = [];
if (dataProvider != null)
{
for each (var row: Object in dataProvider)
{
var rowId: int = int(row.rowId);
for (var key: Object in row)
{
if (key != 'rowId' && key != 'name')
{
var colId: int = int(key);
var value: Boolean = Boolean(row[key]);
if (colId > 0 && value)
{
result.push({ rowId: rowId, colId: colId, value: value });
}
}
}
}
}
return result;
}
/**
* 将服务器返回的数据解析为可在DataGrid中显示的数据
*/
private function parse(src: Object): ArrayCollection
{
var result: ArrayCollection = new ArrayCollection();
for each (var row: Object in src.rows)
{
var item: Object = { rowId: row.id, label: row.name };
for each (var col: Object in src.columns)
item[col.id] = getItemValue(src, row.id, col.id);
result.addItem(item);
}
return result;
}
private function getItemValue(src: Object, rowId: int, colId: int): Boolean
{
for each (var item: Object in src.items)
{
if (item.rowId == rowId && item.colId == colId && item.value)
return true;
}
return false;
}
}
}
import flash.events.*;
import mx.containers.*;
import mx.controls.*;
class MatrixItemRenderer extends HBox
{
public function MatrixItemRenderer()
{
setStyle('borderStyle', 'none');
setStyle('horizontalAlign', 'center');
_chk = new CheckBox();
_chk.addEventListener(Event.CHANGE, onChange);
addChild(_chk);
}
public override function set data(value: Object): void
{
super.data = value;
if (dataField != null && dataField in value)
{
var fieldValue: Boolean = Boolean(value[dataField]);
_chk.selected = fieldValue;
}
}
private function onChange(event: Event): void
{
if (dataField != null && data != null)
data[dataField] = _chk.selected;
}
private var _chk: CheckBox;
public var dataField: String;
}
代码比较长,不过大部分只是简单的数据整理,重要的只有动态生成ClassFactory的部分:
var cf: ClassFactory = new ClassFactory(MatrixItemRenderer);
cf.properties = { dataField: col.dataField };
col.itemRenderer = cf;
以及itemRenderer中获取对应列的部分:
public override function set data(value: Object): void
{
super.data = value;
if (dataField != null && dataField in value)
{
var fieldValue: Boolean = Boolean(value[dataField]);
_chk.selected = fieldValue;
}
}
public var dataField: String;