我需要创建一个具有以下特征的表:
- 13 列:第一列包含不可编辑的文本,其他列包含可编辑或不可编辑的数值,具体取决于行索引
- 3 行:第 1 行包含 int,第 2 行包含双格式为 #,##0.00,第 3 行包含双格式为 #,#0.0%
该表还必须具有可编辑单元格的以下数据验证选项:
- boolean positive:如果允许正数,则为 true
- 布尔负数:如果允许负数则为真
- boolean maxEnabled:如果单元格的值必须小于 maxValue,则为 true
- double maxValue:最大允许值(如果 maxEnabled==true;)
我设法让桌子按照我的意愿行事,我唯一没能开始工作的是:
- 输入成功后,使用我的数字格式格式化新值
- 当用户点击重绘按钮时,获取要重绘的表格
对此的任何帮助将不胜感激。
这是我正在使用的代码:
单元格、列和 FieldUpdater
public class DataCell2 extends EditTextCell{
private TableDTO tableData;
public DataCell2(TableDTO tableData){
this.tableData=tableData;
}
@Override
public void render(com.google.gwt.cell.client.Cell.Context context, String value, SafeHtmlBuilder sb){
super.render(context,value,sb);
}
@Override
public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event,
ValueUpdater<String> valueUpdater){
// If cell non editable exit
if(!isEditable(context)){
return;
}else{
super.onBrowserEvent(context,parent,value,event,valueUpdater);
}
}
private boolean isEditable(Context context){
int row=context.getIndex();
// int column=context.getColumn();
return tableData.isRowEditable(row);
}
public class DataColumn2<DataCell2> extends Column<RowDTO,String>{
public int col;
public DataColumn2(int col, Cell<String> cell){
super(cell);
this.col=col;
}
@Override
public String getValue(RowDTO object){
// TODO Auto-generated method stub
return null;
}
public class LabelColumn2 extends TextColumn<RowDTO>{
public LabelColumn2(){
super();
}
@Override
public String getValue(RowDTO object){
return object.getLabel();
}
public class DataUpdater2 implements FieldUpdater<RowDTO,String>{
private CellTable<RowDTO> table;
private DataCell2 dataCell;
// private ProvidesKey<DataItem> KEY_PROVIDER;
protected int col=0;
public DataUpdater2(int col, CellTable<RowDTO> table, DataCell2 dataCell){
this.dataCell=dataCell;
this.table=table;
this.col=col;
}
public void clear(int index){
// Clear invalid input
dataCell.clearViewData(index);
// Redraw the table.
table.redraw();
}
@Override
public void update(int index, RowDTO object, String value){
// TODO Auto-generated method stub
}
包含标签的行类和行数据及其数据验证类
public class RowDTO{
private final int index;
private Vector<Object> rowData;
private RowValidation validation;
private boolean editable;
public RowDTO(int index, Vector<Object> rowData, int type){
this.index=index;
this.rowData=rowData;
this.validation=buildValidation(index,type);
}
public int getIndex(){
return index;
}
public Vector<Object> getRowData(){
return rowData;
}
public RowValidation getValidation(){
return validation;
}
public String getRowData(int column){
return rowData.get(column).toString();
}
public String getLabel(){
return rowData.get(0).toString();
}
public void setRowData(int column, String newVal){
this.rowData.set(column,newVal);
}
/** Assign a vaildation and editing strategy based on the table type and the row */
private RowValidation buildValidation(int index, int type){
switch(type){
case TableDTO.FIXEDCOST:
switch(index){
case 0:
editable=true;
return RowValidation.getPositiveDouble();
case 1:
editable=true;
return RowValidation.getPositiveInt();
case 2:
editable=true;
return RowValidation.getPositivePercent();
default:
editable=true;
return RowValidation.getPositiveDouble();
}
default:
editable=true;
return RowValidation.getPositiveDouble();
}
}
public boolean isEditable(){
return editable;
}
public class RowValidation{
/* Is double (else is int) */
private boolean digit=true;
/* Values permitted */
private boolean positive=true;
private boolean negative=true;
private boolean zero=true;
private boolean maxEnabled=false;
private double maxValue=2;
/** Default constructor: double number, can be positive, negative or zero, no maximum */
public RowValidation(){}
/**
* @param digit: true if double, false if int
* @param positive: true if can be positive
* @param negative: true if can be negative
* @param zero: true if can be zero
* @param maxEnabled: true if can has maximum
* @param maxValue: maximum value if has maximum
*/
public RowValidation(boolean digit, boolean positive, boolean negative, boolean zero, boolean maxEnabled,
double maxValue){
this.digit=digit;
this.positive=positive;
this.negative=negative;
this.zero=zero;
this.maxEnabled=maxEnabled;
this.maxValue=maxValue;
}
public boolean isDigit(){
return digit;
}
public boolean isPositive(){
return positive;
}
public boolean isNegative(){
return negative;
}
public boolean isZero(){
return zero;
}
public boolean isMaxEnabled(){
return maxEnabled;
}
public double getMaxValue(){
return maxValue;
}
/** Positive or zero Integer */
public static RowValidation getPositiveInt(){
return new RowValidation(false,true,false,true,false,2);
}
/** Positive or zero double */
public static RowValidation getPositiveDouble(){
return new RowValidation(true,true,false,true,false,2);
}
/** Positive double belonging to [0,1] */
public static RowValidation getPositivePercent(){
return new RowValidation(true,true,false,true,true,1);
}
包含行列表的 Table 类:
public class TableDTO{
public static final int FIXEDCOST=0;
private ArrayList<RowDTO> rows;
private Vector<String> headers;
public TableDTO(Vector<Vector<Object>> roughData, Vector<String> headers, int type){
this.headers=headers;
rows=buildRows(roughData,type);
}
private ArrayList<RowDTO> buildRows(Vector<Vector<Object>> roughData, int type){
int nb=roughData.size();
ArrayList<RowDTO> result=new ArrayList<RowDTO>(nb);
for(int i=0;i<nb;i++){
result.add(new RowDTO(i,roughData.get(i),type));
}
return result;
}
public ArrayList<RowDTO> getRows(){
return rows;
}
public RowDTO getRow(int index){
return rows.get(index);
}
public boolean isRowEditable(int index){
return getRow(index).isEditable();
}
public String getHeader(int column){
return headers.get(column);
}
将所有东西结合在一起的面板
public class TablePanel extends Composite{
private VerticalPanel main=new VerticalPanel();
private HorizontalPanel btns=new HorizontalPanel();
private Button commitButton=new Button("commit");
private Button redrawButton=new Button("redraw");
private List<DataChange> pendingChanges=new ArrayList<DataChange>();
private CellTable<RowDTO> table;
private TableDTO dataDTO;
/**
* The key provider that allows us to identify data points even if a field changes.
*/
private static final ProvidesKey<RowDTO> KEY_PROVIDER=new ProvidesKey<RowDTO>(){
@Override
public Object getKey(RowDTO item){
return item.getIndex();
}
};
@SuppressWarnings({"unchecked"})
public TablePanel(Vector<Vector<Object>> roughData, Vector<String> headers, int type){
dataDTO=new TableDTO(roughData,headers,type);
// Create a CellTable with a key provider.
table=new CellTable<RowDTO>(KEY_PROVIDER);
table.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
// Label
LabelColumn2 nameColumn=new LabelColumn2();
table.addColumn(nameColumn,"Label");
redrawButton.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event){
// Delete temporary changes
pendingChanges.clear();
// Redraw table
table.setRowData(0,dataDTO.getRows());
table.redraw();
}
});
commitButton.addClickHandler(new ClickHandler(){
@Override
public void onClick(ClickEvent event){
// Commit the changes.
for(DataChange pendingChange: pendingChanges){
pendingChange.doCommit();
}
pendingChanges.clear();
// Push the changes to the views.
table.setRowData(0,dataDTO.getRows());
table.redraw();
}
});
// myData.getCol();
for(int i=1;i<5;i++){
// Create cell
DataCell2 dataCell=new DataCell2(dataDTO);
// Add a column for every data points.
@SuppressWarnings({"rawtypes"})
DataColumn2<DataCell2> dataColumn=new DataColumn2(i,dataCell){
@Override
public String getValue(RowDTO object){
String newVal=object.getRowData(col);
return format(object,newVal);
}
};
// Add a field updater to be notified when the user enters a new value.
dataColumn.setFieldUpdater(new DataUpdater2(i,table,dataCell){
@Override
public void update(int index, RowDTO object, String value){
// Called when the user changes the value.
if(isValidValue(index,value)){
pendingChanges.add(new DataChange(this.col,object,value));
// TODO kill once ok
int s=pendingChanges.size();
String ss=object.getRowData(col);
Window.alert("Value in myData="+ss+", nb pending changes="+s);
}else{
/* clear the view data and redraw the table */
this.clear(index);
// Alert user: TODO restablish once ok
// Window.alert("Invalid input");
// TODO kill once ok
int s=pendingChanges.size();
String ss=object.getRowData(col);
Window.alert("Value in myData="+ss+", nb pending changes="+s);
}
}
});
table.addColumn(dataColumn,dataDTO.getHeader(i));
}
// Set the total row count. This isn't strictly necessary, but it affects
// paging calculations, so its good habit to keep the row count up to date.
table.setRowCount(dataDTO.getRows().size(),true);
// Push the data into the widget.
table.setRowData(0,dataDTO.getRows());
// Add it to the root panel.
main.add(table);
btns.add(commitButton);
btns.add(redrawButton);
main.add(btns);
initWidget(main);
}
/* Formatting */
private String format(RowDTO row, String value){
RowValidation rv=row.getValidation();
if(rv.isDigit()){
if(rv.isMaxEnabled()){
return formatAsPercent(value);
}else{
return formatAsDouble(value);
}
}else{
return formatAsInt(value);
}
}
private static String formatAsDouble(String val){
try{
double value=Double.parseDouble(val);
NumberFormat fmt=NumberFormat.getDecimalFormat();
fmt.overrideFractionDigits(2,2);
String formatted=fmt.format(value);
return formatted;
}catch(NumberFormatException e){
// TODO
return val;
}
}
private static String formatAsInt(String val){
try{
double value=Double.parseDouble(val);
NumberFormat fmt=NumberFormat.getDecimalFormat();
fmt.overrideFractionDigits(0,0);
String formatted=fmt.format(value);
return formatted;
}catch(NumberFormatException e){
// TODO
return val;
}
}
private static String formatAsPercent(String val){
try{
double value=Double.parseDouble(val);
NumberFormat fmt=NumberFormat.getPercentFormat();
fmt.overrideFractionDigits(2,2);
String formatted=fmt.format(value);
return formatted;
}catch(NumberFormatException e){
// TODO
return val;
}
}
private boolean isValidValue(int index, String data){
/* if data formatted as pct, convert into double */
if(data.endsWith("%")){
data=data.substring(0,data.length()-2);
try{
double v=Double.parseDouble(data);
v=v/100;
data=Double.toString(v);
}catch(NumberFormatException e){
return false;
}
}
RowDTO row=dataDTO.getRow(index);
RowValidation validation=row.getValidation();
if(validation.isDigit()){
double val;
try{
val=Double.parseDouble(data);
}catch(Exception e){
return false;
}
if(val>0&&!validation.isPositive()){ return false; }
if(val<0&&!validation.isNegative()){ return false; }
if(val==0&&!validation.isZero()){ return false; }
if(validation.isMaxEnabled()&&val>validation.getMaxValue()){ return false; }
}else{
int val;
try{
val=Integer.parseInt(data);
}catch(Exception e){
return false;
}
if(val>0&&!validation.isPositive()){ return false; }
if(val<0&&!validation.isNegative()){ return false; }
if(val==0&&!validation.isZero()){ return false; }
if(validation.isMaxEnabled()&&val>validation.getMaxValue()){ return false; }
}
return true;
}
private class DataChange{
private final RowDTO object;
private final String value;
private final int col;
public DataChange(int col, RowDTO object, String value){
this.object=object;
this.value=value;
this.col=col;
}
public void doCommit(){
object.setRowData(col,value);
}
}
以及入口点方法:
public class Mpp implements EntryPoint{
/** Entry point method. */
@Override
public void onModuleLoad(){
int a=3;
int b=13;
Vector<Vector<Object>> roughData=new Vector<Vector<Object>>(a);
Vector<String> headers=new Vector<String>(b);
Vector<Object> r0=new Vector<Object>(b);
Vector<Object> r1=new Vector<Object>(b);
Vector<Object> r2=new Vector<Object>(b);
r0.add("Amount (double)");
r1.add("Credit (int)");
r2.add("Advance (%)");
headers.add("Col ");
for(int i=1;i<b;i++){
headers.add("Col "+(i));
r0.add(i*1.2);
r1.add(i);
r2.add(i/100);
}
roughData.add(r0);
roughData.add(r1);
roughData.add(r2);
TablePanel panel=new TablePanel(roughData,headers,TableDTO.FIXEDCOST);
RootPanel.get().add(panel);
}