您的位置:首页 > 其它

Ext Grid 的合计行解决

2008-10-17 13:20 281 查看
在实际的应用中,我们的用户经常会要求需要在展现数据的网格上,增加合计行这样的功能,Ext.Grid.GridPanel本身并不支持合计行,在EXT的官方论坛上,有一些plugin可以实现合计行的功能。但其解决的个人觉得不太好用,于是,只有自己手动来做了。
首先,我们要搞清楚,grid控件,是与ColumnModel,Store,GridView等对象一起协作地,所以要分析需要从什么地方入手解决问题。经过分析,我们不难看出,要解决我们的合计行,需要从以下几方面入手:
1.改变表格VIEW的header模板,增加我们的合计行元素
2.增加对表格数据的求和计算
3.考虑表格中数据变化时,刷新数据视图的问题
4.修改renderHeader方法,以支持合计行数据的渲染
以下为新增的CSS样式:
.x-grid3-row-sum {
/*border:1px solid #dddddd;
background: #efefef url(../images/default/grid/grid3-hrow-sum.gif) repeat-x left top;
*/
border:1px solid #dddddd;
background: url(../images/default/grid/grid3-hrow-sum.gif) repeat-x left top;
}

http://p.blog.csdn.net/images/p_blog_csdn_net/ynzhangyao/EntryImages/20081017/grid3-hrow-sum.gif

示例图:
http://p.blog.csdn.net/images/p_blog_csdn_net/ynzhangyao/EntryImages/20081017/ext_grid_sum.JPG

/*

* Ext JS Library 2.1

* Copyright(c) 2006-2008, Ext JS, LLC.

* licensing@extjs.com

*

* http://extjs.com/license
*/

/**

* @class Ext.grid.EditorGridPanelEx

* @extends Ext.grid.EditorGridPanel

* @author 张尧伟

* @version 1.0

* <p>此类是为增加合计行而设计的</p>

* <br><br>Usage:

* <pre><code>

function createPreplanDetailGrid()

{

var preplanDetailStore = new Ext.data.DWRStore({id:'preplanDetailStore',fn:UIPreContractReport.getPreContractDetail,

fields: [

{name: 'bar'},

{name: 'itemName'},

{name: 'storeAmount', type: 'float'},

{name: 'endAmount',type:'float'},

{name: 'currentRate',type:'float'},

{name: 'weekPercent',type:'float'},

{name: 'confirmAmount',type:'float'},

{name: 'accPreAmount',type:'float'},

{name: 'surplusTargetAmount',type:'int'},

{name:'surplusHyearAmount',type:'float'}

]

});

var sm = new Ext.grid.CheckboxSelectionModel();

var preplanDetailGrid = new Ext.grid.EditorGridPanelEx({

id:'preplanDetailGrid',

title:'卷烟规格明细',

store: preplanDetailStore,

cm: new Ext.grid.ColumnModelEx({sumheader:true,columns:[

sm,

{header: "卷烟条码", width:90, sortable: true, dataIndex: 'bar',sumcaption:'合计'},

{header: "卷烟规格", width:110,sortable: true, dataIndex: 'itemName'},

{header: "预计划量", width:100,sortable: true, dataIndex: 'endAmount',editor:new Ext.form.NumberField(),align:'right',renderer:Util.rmbMoney,issum:true},

{header: "商业库存", width:100,sortable: true, dataIndex: 'storeAmount',align:'right',renderer:Util.rmbMoney},

{header: "到货存销比", width:100,sortable: true, dataIndex: 'currentRate',align:'right',renderer:Util.rmbMoney},

{header: "周进度", width:100,sortable: true, dataIndex: 'weekPercent',align:'right'},

{header: "商业请求量", width:100,sortable: true, dataIndex: 'confirmAmount',align:'right',renderer:Util.rmbMoney,issum:true},

{header: "累计预计划量", width:100,sortable: true, dataIndex: 'accPreAmount',align:'right',renderer:Util.rmbMoney},

{header: "剩余指标量", width:100,sortable: true, dataIndex: 'surplusTargetAmount',align:'right',renderer:Util.rmbMoney,issum:true},

{header: "剩余协议量", width:100,sortable: true, dataIndex: 'surplusHyearAmount',align:'right',renderer:Util.rmbMoney,issum:true}

]}),

sm:sm,

stripeRows: true,

height:Util.getH(0.4),

bbar:[

{pressed:true,text:'删除',handler:deletePreplanDetail},{xtype:'tbseparator'},

{pressed:true,text:'保存',handler:saveModified}

]

});

return preplanDetailGrid;

}

</code></pre>

* <b>Notes:</b> <br/>

* - Ext.grid.ColumnModel需要增加属性:sumheader:true以指示需要使用合计行

* - Ext.grid.ColumnModel的columns属性中,需要增加sumcaption:'合计'属性,以指示需要显示的合计标题名称

* - Ext.grid.ColumnModel的columns属性中,需要增加issum:true属性,以指示该列需要计算合计

* - Ext.grid.ColumnModel的columns属性中,可选增加sfn:function(sumvalue,colvalue,record){return 计算结果;},

* 以指示该列需要使用用户自定义函数进行计算sumvalue:此列当前的合计值,colvalue当前计算的列值,record当前记录对象

* <br>

* @constructor

* @param {Object} config The config object

*/

Ext.grid.GridPanelEx = Ext.extend(Ext.grid.GridPanel, {

getView : function() {

if (!this.view) {

this.view = new Ext.grid.GridViewEx(this.viewConfig);

}

return this.view;

},

initComponent : function() {

if (!this.cm) {

this.cm = new Ext.grid.ColumnModelEx(this.columns);

this.colModel = this.cm;

delete this.columns;

}

if(!this.groupedHeaders)

{

this.groupedHeaders = this.groupedHeaders;

}

//在编辑完成后,需要更新合计列

//this.on('afteredit',this.onAfteredit,this);

Ext.grid.GridPanelEx.superclass.initComponent.call(this);

},

getGroupedHeaders : function(){

return this.groupedHeaders;

},

/**

* 处理修改后,更新合计

* @param {} event

* grid - This grid

* record - The record being edited

* field - The field name being edited

* value - The value being set

* originalValue - The original value for the field, before the edit.

* row - The grid row index

* column - The grid column index

*/

onAfteredit:function(event){

var grid = event.grid;

var cm = grid.getColumnModel();

if(false == cm.sumheader)

{

return;

}

var value = event.value;

var origValue = event.originalValue;

cm.config[event.column].sumvalue -= origValue;

cm.config[event.column].sumvalue += value;

grid.getView().updateHeaders();

},

/**

* 重新计算合计列

*/

recalculation:function(){

var cm = this.getColumnModel();

if(true != cm.sumheader)

{

return;

}

var view = this.getView();

view.recalculation(this.getStore());

}

});

Ext.grid.EditorGridPanelEx = Ext.extend(Ext.grid.EditorGridPanel, {

getView : function() {

if (!this.view) {

this.view = new Ext.grid.GridViewEx(this.viewConfig);

}

return this.view;

},

initComponent : function() {

if (!this.cm) {

this.cm = new Ext.grid.ColumnModelEx(this.columns);

this.colModel = this.cm;

delete this.columns;

}

if(!this.groupedHeaders)

{

this.groupedHeaders = this.groupedHeaders;

}

//在编辑完成后,需要更新合计列

this.on('afteredit',this.onAfteredit,this);

Ext.grid.EditorGridPanelEx.superclass.initComponent.call(this);

},

getGroupedHeaders : function(){

return this.groupedHeaders;

},

/**

* 处理修改后,更新合计

* @param {} event

* grid - This grid

* record - The record being edited

* field - The field name being edited

* value - The value being set

* originalValue - The original value for the field, before the edit.

* row - The grid row index

* column - The grid column index

*/

onAfteredit:function(event){

var grid = event.grid;

var cm = grid.getColumnModel();

if(false == cm.sumheader)

{

return;

}

var value = event.value;

var origValue = event.originalValue;

cm.config[event.column].sumvalue -= origValue;

cm.config[event.column].sumvalue += value;

grid.getView().updateHeaders();

},

/**

* 重新计算合计列

*/

recalculation:function(){

var cm = this.getColumnModel();

if(true != cm.sumheader)

{

return;

}

var view = this.getView();

view.recalculation(this.getStore());

}

});

Ext.grid.GridViewEx = function(config) {

Ext.apply(this, config);

if (!this.templates) this.templates = {};

//增加合计行模板

if(!this.templates.header){

this.templates.header = new Ext.Template(

'<table border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',

'<thead><tr class="x-grid3-hd-row">{cells}</tr><tr class="x-grid3-hd-row x-grid3-row-sum">{sumcells}</tr></thead>',

"</table>"

);

}

if(!this.templates.sumcells){

this.templates.sumcells = new Ext.Template(

'<td class="x-grid3-hd x-grid3-cell x-grid3-td-{id}" style="{style}"><div {tooltip} {attr} class="x-grid3-hd-inner x-grid3-hd-{id}" unselectable="on" style="{istyle}">', '',

'{value}', '', '',

"</div></td>"

);

}

Ext.grid.GridViewEx.superclass.constructor.call(this);

};

Ext.extend(Ext.grid.GridViewEx, Ext.grid.GridView, {

insertRows : function(ds, firstRow, lastRow, isUpdate){

if(!isUpdate && firstRow === 0 && lastRow == ds.getCount()-1){

this.refresh();

}else{

if(!isUpdate){

this.fireEvent("beforerowsinserted", this, firstRow, lastRow);

}

var html = this.renderRows(firstRow, lastRow);

var before = this.getRow(firstRow);

if(before){

Ext.DomHelper.insertHtml('beforeBegin', before, html);

}else{

Ext.DomHelper.insertHtml('beforeEnd', this.mainBody.dom, html);

}

if(!isUpdate){

this.fireEvent("rowsinserted", this, firstRow, lastRow);

this.processRows(firstRow);

}

}

},

onUpdate : function(ds, record){

this.refreshRow(record);

},

// private

refreshRow : function(record){

var ds = this.ds, index;

if(typeof record == 'number'){

index = record;

record = ds.getAt(index);

}else{

index = ds.indexOf(record);

}

var cls = [];

this.insertRows(ds, index, index, true);

this.getRow(index).rowIndex = index;

this.onRemove(ds, record, index+1, true);

this.fireEvent("rowupdated", this, index, record);

/*

if(true == record.dirty && true == this.cm.sumheader){

var cm = this.cm;

var colCount = cm.getColumnCount();

for(var i=0; i<colCount;++i)

{

var c = cm.config[i];

if( true == c.issum && typeof record.modified[c.dataIndex] !== 'undefined'){

var value = record.get(c.dataIndex);

var origValue = record.modified[c.dataIndex];

if(origValue){

cm.config[i].sumvalue -= origValue;

cm.config[i].sumvalue += value;

}

}

}

this.updateHeaders();

}*/

},

onRemove : function(ds, record, index, isUpdate){

if(isUpdate !== true){

this.fireEvent("beforerowremoved", this, index, record);

}

this.removeRow(index);

if(isUpdate !== true){

this.processRows(index);

this.applyEmptyText();

this.fireEvent("rowremoved", this, index, record);

//处理删除行时的合计行问题

this.processSumForRemoved(ds,record,index);

}

},

//Template has changed and we need a few other pointers to keep track

doRender : function(cs, rs, ds, startRow, colCount, stripe){

var ts = this.templates, ct = ts.cell, rt = ts.row, last = colCount-1;

var tstyle = 'width:'+this.getTotalWidth()+';';

// buffers

var buf = [], cb, c, p = {}, rp = {tstyle: tstyle}, r;

//如果不是在编辑状态下,则需要将合计列的数据清0

if(false == rs[0].dirty && true ==(rs.length == ds.getCount())){

this.clearSumZero();

}

for(var j = 0, len = rs.length; j < len; j++){

r = rs[j]; cb = [];

var rowIndex = (j+startRow);

for(var i = 0; i < colCount; i++){

c = cs[i];

p.id = c.id;

p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');

p.attr = p.cellAttr = "";

p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);

p.style = c.style;

if(p.value == undefined || p.value === "") p.value = " ";

if(r.dirty && typeof r.modified[c.name] !== 'undefined'){

p.css += ' x-grid3-dirty-cell';

}

cb[cb.length] = ct.apply(p);

//处理求和问题

if(true == this.cm.sumheader)

{

if(true == this.cm.config[i].issum && false == r.dirty)

{//如果是求和列且不为脏数据

if(!this.cm.config[i].sumvalue){

this.cm.config[i].sumvalue = 0.0;

}

if(this.cm.config[i].sfn)

{//如果存在求和函数,则调用

this.cm.config[i].sumvalue = this.cm.config[i].sfn(this.cm.config[i].sumvalue,r.get(c.name),r);

}

else

{//否则,直接累计

if(r.data[c.name]){

this.cm.config[i].sumvalue += r.data[c.name];

}

}

}

}

}

var alt = [];

if(stripe && ((rowIndex+1) % 2 == 0)){

alt[0] = "x-grid3-row-alt";

}

if(r.dirty){

alt[1] = " x-grid3-dirty-row";

}

rp.cols = colCount;

if(this.getRowClass){

alt[2] = this.getRowClass(r, rowIndex, rp, ds);

}

rp.alt = alt.join(" ");

rp.cells = cb.join("");

buf[buf.length] = rt.apply(rp);

}

//如果有合计行,则需要重新渲染表头

if(true == this.cm.sumheader)

{

this.updateHeaders();

}

return buf.join("");

},

/**

* 将求和的列清0

*/

clearSumZero:function(){

this.hasSumColumn = false;

var cm = this.cm;

for(var i=0; i<cm.config.length;++i)

{

if(cm.config[i].issum)

{

this.hasSumColumn = true;

this.cm.config[i].sumvalue = 0.0;

}

}

},

renderHeaders : function(){

var cm = this.cm, ts = this.templates;

var ct = ts.hcell;

var cb = [], sb = [],lb = [], lsb = [], p = {};

for(var i = 0, len = cm.getColumnCount(); i < len; i++){

p.id = cm.getColumnId(i);

p.value = cm.getColumnHeader(i) || "";

p.style = this.getColumnStyle(i, true);

p.tooltip = this.getColumnTooltip(i);

if(cm.config[i].align == 'right'){

p.istyle = 'padding-right:16px';

} else {

delete p.istyle;

}

cb[cb.length] = ct.apply(p);

}

//处理合计行表头

if(true == cm.sumheader)

{

sb = this.buildSumHeaders(cm,ts);

}

return ts.header.apply({cells: cb.join(""), sumcells: sb.join(""),tstyle:'width:'+this.getTotalWidth()+';'});

//return [ts.header.apply({cells: cb.join(""), sumcells: sb.join(""), tstyle:'width:'+(tw-lw)+';'}),

//ts.header.apply({cells: lb.join(""), sumcells: lsb.join(""), tstyle:'width:'+(lw)+';'})];

//return ts.header.apply({cells: cb.join(""), tstyle:'width:'+this.getTotalWidth()+';'});

},

/**

* 生成合计表头

* @param {} cm

* @param {} ts

* @param {} tw

* @param {} lw

* @return {}array

*/

buildSumHeaders:function(cm,ts){

var ct = ts.hcell;

var sb = [], sp = {};

for (var i = 0, len = cm.getColumnCount(); i < len; i++) {

sp.id = 'sum' + cm.getColumnId(i);

if(cm.config[i].sumcaption){

sp.value = cm.config[i].sumcaption;

}else{

sp.value = " ";

}

//cm.config[i].sumcaption = " ";

if (true == cm.config[i].issum && typeof cm.config[i].sumvalue == 'number'){

if(cm.config[i].renderer)

{

sp.value = cm.config[i].renderer(cm.config[i].sumvalue);

}else{

sp.value = cm.config[i].sumvalue;

}

}

sp.style = this.getColumnStyle(i, false);

sp.tooltip = this.getColumnTooltip(i);

if (cm.config[i].align == 'right') {

sp.istyle = 'padding-right:16px';

}

sb[sb.length] = ct.apply(sp);

}

return sb;

},

/**

* 处理删除行时,更新合计行的数据

* @param {} ds

* @param {} record

* @param {} index

*/

processSumForRemoved: function(ds,record,index){

var cm = this.cm;

if(true != cm.sumheader){

return;

}

var cfg = cm.config;

for(var i=0; i<cfg.length; ++i){

if(true == cfg[i].issum && cfg[i].sumvalue){

var val = record.get(cfg[i].dataIndex);

if(val){

cfg[i].sumvalue -= val;

}

}

}

this.updateHeaders();

},

/**

* 重新计算合计列

*/

recalculation:function(ds){

this.clearSumZero();

if(true != this.hasSumColumn){

return;

}

var colCount = this.cm.getColumnCount();

var records = ds.getRange();

for(var k=0; k<records.length; ++k){

record = records[k];

for(var i=0; i<this.cm.config.length; ++i){

if(true == this.cm.config[i].issum){

var val = record.get(this.cm.config[i].dataIndex);

if(typeof val == 'number'){

this.cm.config[i].sumvalue += val;

}

}

}

};

this.updateHeaders();

}

});

Ext.grid.ColumnModelEx = function(config) {

Ext.grid.ColumnModelEx.superclass.constructor.call(this, config);

//alert('config.groupedHeaders ' + config.groupedHeaders);

//this.groupedHeaders = config.groupedHeaders;

};

Ext.extend(Ext.grid.ColumnModelEx, Ext.grid.ColumnModel, {

/**

* Returns true if the specified column menu is disabled.

* @param {Number} col The column index

* @return {Boolean}

*/

isMenuDisabled : function(col){

if(-1 == col){

return true;

}else{

return !!this.config[col].menuDisabled;

}

}

});

Ext.reg('gridex', Ext.grid.GridPanelEx);

Ext.reg('editorgridex', Ext.grid.EditorGridPanelEx);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: