移花接木 实例讲解Ext JS控件的扩展(1)(2)
移Property Grid之花接EditorGrid之木
首先,介绍一下我们的场景和实际需求。某大学要建设一个教职工科研基金的管理系统,该系统可供基金设置人员设置基金申请条件、发放步骤等,申请人员填报申请人信息、申领基金等。这里以构建一个基金申请条件的组件为例。条件制定人员在制定申请条件时,可以随意添加、删除申请条件;对于某些申请条件,比如院系、性别等要求系统能提供预先定义好的选项供条件制定人员选择,而对于比如特长、年龄等内容不明确的或者选项过多无法列举的情况,则直接提供输入框供条件制定人员输入。
为了用Ext构建这样的组件,我们首先想到的是选用EditorGrid组件或者Property Grid组件。EditorGrid(可编辑表格控件)扩展自GridPanel,提供对于选中列的单元格编辑。可编辑的列是通过在表示表格的列信息的类Ext.grid.ColumnModel中添加editor来实现的。但是这个editor是对整个列有效的,就是说每一行在该列的位置的数据的编辑器是一样的。
Property Grid(属性表格)扩展自EditorGridPanel,所以可以直接编辑右边属性值部分的内容。但是,只是右边的,即使你单击左边的单元格,编辑器也只会出现在右边。实际上,我们可以用散列表来形容Property Grid,左边可以看作key,右边的是value。key是由我们指定好的,用户只需要修改对应的value即可。
Property Grid默认的编辑器包括TextField、DateField、NumberField和ComboBox,也就只能处理数字、字符串的输入和日期的选择,布尔值的选择等一般的情况。当我们想对编辑器进行更详细的配置时,就需要用到Property Grid的customEditors,为指定id的那行数据设置对应的编辑器。customEditors和source的设置基本一样,只需要将两者的属性名称对应起来,并且为customEditors里的所有属性指定一个editor。
Property Grid虽然能够给不同的单元格定制不同的编辑器,但是一方面这种表格只有两列,第一列还不可编辑,而且表格的内容(source)需要事先确定;另一方面定义customEditors的时候必须知道表格的内容(source),而且必须将两者的属性名称对应起来。EditorGrid其实已经大部分满足了我们的需求,只是不能对每个单元格定制编辑器,只能指定列编辑器。
经过上面的分析,单纯的使用任何一个控件,都难以达到我们的目的。同时我们发现问题主要出在EditorGrid的列模式(ColumnModel)上,Property Grid就是扩展自EditorGrid,通过对其ColumnModel的扩展来支持单元格的编辑器。所以我们尝试把EditorGrid的ColumnModel扩展一下,使得新的ColumnModel支持customEditors,这样我们就获得了对编辑器的完全控制权,可以根据表格的内容动态的改变单元格的编辑器了。清单3是我们为满足上述需求而扩展的新类MyColumnModel的部分代码,清单4是使用MyColumnModel构造了一个EditorGrid作为基金申请条件组件。
- 清单3.定义新类MyColumnModel
- Ext.ns('Ext.ux.grid');
- //新类MyColumnModel的构造函数
- Ext.ux.grid.MyColumnModel=function(grid,store,column){
- this.grid=grid;
- this.store=store;
- vargender=[
- ['0100','男'],
- ['0101','女']
- ];
- vardepartment=[
- ['0200','文学院'],
- //省略部分代码
- ['0207','医学部']
- ];
- vartitle=[
- ['0300','助教'],
- //省略部分代码
- ['0303','教授']
- ];
- vargenderCombo=newExt.form.ComboBox({
- store:newExt.data.SimpleStore({
- fields:['value','text'],
- data:gender
- }),
- emptyText:'请输入',
- mode:'local',
- triggerAction:'all',
- valueField:'value',
- displayField:'text',
- readOnly:true
- });
- vardepartmentCombo=newExt.form.ComboBox({
- store:newExt.data.SimpleStore({
- fields:['value','text'],
- data:department
- }),
- //与上面定义genderCombo类似,故省略部分代码
- …
- });
- vartitleCombo=newExt.form.ComboBox({
- store:newExt.data.SimpleStore({
- fields:['value','text'],
- data:title
- }),
- //与上面定义genderCombo类似,故省略部分代码
- …
- });
- //当选择“性别”、“院系”、“职称”时,提供相应的下拉列表作为单元格编辑器,
- 供用户选择;当选择“年龄”、“论文数量”时,提供数字文本框供用户输入
- this.customEditors={
- 'GENDER':newExt.grid.GridEditor(genderCombo),
- 'DEPARTMENT':newExt.grid.GridEditor(departmentCombo),
- 'TITLE':newExt.grid.GridEditor(titleCombo),
- 'AGE':newExt.grid.GridEditor(newExt.form.NumberField({selectOnFocus:true,
- style:'text-align:left;'})),
- 'PAPER':newExt.grid.GridEditor(newExt.form.NumberField({selectOnFocus:true,
- style:'text-align:left;'}))
- };
- Ext.ux.grid.MyColumnModel.superclass.constructor.call(this,column);
- };
- Ext.extend(Ext.ux.grid.MyColumnModel,Ext.grid.ColumnModel,{
- //通过覆盖父类中的方法getCellEditor,实现根据表达式中条件列的不同取值,
- 为表达式的值所在单元格返回不同的编辑器
- getCellEditor:function(colIndex,rowIndex){
- varp=this.store.getAt(rowIndex);
- n=p.data.attrName;//对应表达式的条件列的取值
- if(colIndex==4)//表达式的值propertyValue所在的列
- {
- if(this.customEditors[n]){
- returnthis.customEditors[n];
- }else{
- //如果没有定义特定的单元格编辑器,则返回普通的文本框编辑器
- vared=newExt.grid.GridEditor(newExt.form.TextField({
- selectOnFocus:true
- })
- );
- returned;
- }
- }
- else
- returnthis.config[colIndex].editor;
- }
- });






