JTable增加自动序号&存储自定义数据

简介

为了表格的展示友好性,通常我们会给表格数据增加序号列;实际业务需求中,表格中的行对应的数据并不仅仅是展示在表格上的部分,还需要存储一些额外数据。使用默认的DefaultTableModel有许多缺点:

  • 每个表格都需要修改列标题和数据,增加序号。
  • 需要自己额外维护一套逻辑来存储行展示数据之外的数据。
  • 当表格行进行拖拽后,序号以及表格额外数据部分不能自动调换。

对DefaultTableModel进行扩展

自定义的RowNumberTableModel ,增加了rowDatas成员,每次返回指定数据当前所在的行。并增加了RowOrderChangeListener,使用者可以监听行变化事情,在行发生变更后,执行自己的业务逻辑。构造函数以及addRow方法,都增加了Object data变量,支持给每行绑定一个数据,并提供了getRowData方法,获取该行所绑定的数据。

public class RowNumberTableModel extends DefaultTableModel {
	
    private List rowDatas;
    private RowOrderChangeListener rowOrderChangeListener;

    public RowNumberTableModel(Object[][] data, String[] columns) {
    	super(data, columns);
    }
    
    public <T> RowNumberTableModel(Object[][] data, String[] columns, List<T> rowDatas) {
    	this(data, columns);
    	if (rowDatas != null) {
    		this.rowDatas = rowDatas;
    	}
    }
    
    public void setRowOrderChangeListener(RowOrderChangeListener rowOrderChangeListener) {
    	this.rowOrderChangeListener = rowOrderChangeListener;
    }
    
    @SuppressWarnings("unchecked")
	public <T> T getRowData(int rowIndex) {
    	if (rowDatas.size() > rowIndex) {
    		return (T)rowDatas.get(rowIndex);
    	}
    	return null;
    }
    
    @SuppressWarnings("unchecked")
	public <T> List<T> getRowDatas() {
		return rowDatas;
	}
    
    public void swapRowData(int from, int to) {
    	Object fromData = rowDatas.get(from);
    	Object toData = rowDatas.get(to);
    	rowDatas.set(from, toData);
    	rowDatas.set(to, fromData);
    	if (rowOrderChangeListener != null) {
    		rowOrderChangeListener.afterRowOrderChange(this, from, to);
    	}
    }

	@Override
	public void addRow(Object[] data) {
		super.addRow(data);
		if (this.rowDatas != null) {
			rowDatas.add(null);
		}
	}
	
	public void addRow(Object[] data, Object rowData) {
		super.addRow(data);
		if (this.rowDatas != null) {
			rowDatas.add(rowData);
		}
	}

	@Override
	public void removeRow(int row) {
		super.removeRow(row);
		if (rowDatas != null) {
			rowDatas.remove(row);
		}
	}

	@Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        if (columnIndex == 0) {
            return rowIndex + 1;
        } else {
        	return super.getValueAt(rowIndex, columnIndex - 1);
        }
    }

    @Override
	public int getColumnCount() {
		return super.getColumnCount() + 1;
	}

	@Override
    public String getColumnName(int column) {
        if (column == 0) {
            return "#";
        } else {
        	return super.getColumnName(column - 1);
        }
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return columnIndex != 0;
    }

    @Override
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
    	if (columnIndex == 0) {
    		return;
    	}
    	super.setValueAt(value, rowIndex, columnIndex - 1);
    }

    @FunctionalInterface
    public interface RowOrderChangeListener {
    	
    	void afterRowOrderChange(RowNumberTableModel model, int from, int to);
    	
    }

自定义数据更新

编辑JTable的单元格时,系统会自动帮忙调用TableModel的setValueAt方法,对表格绑定的数据进行更新,但是我们自己扩展的行数据并不会自动被更新,有以下几种方式可以解决这个问题。

  1. 在自定义的TableModel类中,增加CellDataChangeListener接口,重写setValueAt方法。
public class MyTableModel extends DefaultTableModel {
	
    private List rowDatas;
    private CellDataChangeListener cellDataChangeListener;

	@Override
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
    	super.setValueAt(value, rowIndex, columnIndex - 1);
    	Object rowData = getRowData(rowIndex);
    	if (this.cellDataChangeListener != null && rowData != null) {
			this.cellDataChangeListener.afterCellDataChange(value, columnIndex, rowData);
		}
    }

	@FunctionalInterface
    public interface CellDataChangeListener {
    	
    	void afterCellDataChange(Object value, int columnIndex, Object rowData);
    	
    }
}
  1. 自定义CellEditor,实现getCellEditorValue方法,在其内部对rowData进行更新。
public class TextFieldCellEditor extends DefaultCellEditor {
	private final JTextField textField;
	private MyRowData rowData;
	private int column;
	public TextFieldCellEditor() {
		super(new JTextField());
		this.textField = (JTextField) getComponent();
	}

	@Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        textField.setText(Optional.ofNullable(value).map(String::valueOf).orElse(null));
        this.rowData = ((MyTableModel)table.getModel()).getRowData(row);
        this.column = column;
        return textField;
    }

	@Override
    public Object getCellEditorValue() {
    	Object value = textField.getText();
    	// 更新行绑定的数据
    	if (column = xxx) {
    		this.rowData.setXxx(value);
    	}
    	return value;
    }
}

可以看到,方案二导致代码复用率较低,优先还是推荐方案一通过TableModel回调的方式完成自定义行数据的更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值