Search code examples
javaswingjtabletablemodelabstracttablemodel

Custom Table Model not working


I wrote a custom table model. The goal of it is to bind values to a list. This list is used throughout the application. If a change is made in the table, anywhere else in the application that change is also reflected. My problem is, my table JTable does not display the rows.

This is my first custom table model, so I am not sure if I am missing something.

The table is created with this code:

public CBTable(List<T> elements, Class<T> classType) {
    super(new BindingTableModel(elements));
    this.tableModel = (BindingTableModel<T>) getModel();
    this.classType = classType; 
    setBindings();
    repaint();
}

An example of setBindings is this:

@Override
protected void setBindings() {
    addBinding(ProfessionalDelegate.DELEGAGE_PROPERTY_TYPE,
            "Type",
            String.class,
            false);
    addBinding(ProfessionalDelegate.ENTITY_PROPERTY_NAME,
            "Name",
            String.class,
            true);
     ...

And the actual model itself is this:

public class BindingTableModel<T> extends AbstractTableModel  implements TableModel {

    private List<T> elements;
    private List<BindingTableModelInfo> bindingInfo;

    private Map<Point, Object> valueMap;

    public BindingTableModel(List<T> elements) {
        this.elements = elements;
        this.bindingInfo = new ArrayList<>();
        valueMap = new HashMap<>();
        bind();
        for(int i = 0; i < getRowCount(); i++){
            fireTableRowsInserted(i, i);
        }    
        fireTableStructureChanged();
    }

    public void addBindingInfo(String propertyName, String columnName, Class colClass, boolean isEditable) {
        bindingInfo.add(new BindingTableModelInfo(propertyName,
                columnName,
                colClass,
                isEditable));
    }

    private void bind() {
        for (int col = 0; col < getColumnCount(); col++) {
            for (int row = 0; row < getRowCount(); row++) {
                getValueAt(row, col);//this will init the map
            }
        }
    }

    public void addElement(T element){
        elements.add(element);
    }

    public List<T> getElements(){
        return elements;
    }

    public void removeElement(T element){
        int index = elements.indexOf(element);
        elements.remove(element);
        fireTableRowsDeleted(index, index);
    }

    @Override
    public int getRowCount() {
        return elements.size();
    }

    @Override
    public int getColumnCount() {
        return bindingInfo.size();
    }

    @Override
    public String getColumnName(int i) {
        return bindingInfo.get(i).getColumnName();
    }

    @Override
    public Class<?> getColumnClass(int i) {
        return bindingInfo.get(i).getColumnClass();
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return bindingInfo.get(col).isIsEditable();

    }

    @Override
    public Object getValueAt(int row, int col) {
        Point point = new Point(row, col);
        if (valueMap.containsKey(point)) {
            return valueMap.get(point);
        }
        String property = bindingInfo.get(col).getProperty();
        Class classType = bindingInfo.get(col).getColumnClass();
        T element = elements.get(row);
        Object retVal = Pojo.getValueByName(classType, element, property);
        valueMap.put(point, retVal);
        return retVal;
    }

    @Override
    public void setValueAt(Object value, int row, int col) {
        Point point = new Point(row, col);
        if (valueMap.containsKey(point)) {
            Object oldValue = valueMap.get(point);
            if (oldValue != null && oldValue.equals(value)) {
                return;
            }
        }
        String property = bindingInfo.get(col).getProperty();
        Class classType = bindingInfo.get(col).getColumnClass();
        T element = elements.get(row);
        Pojo.setValueByName(classType, element, property, value);
    }


}

Solution

  • Be certain to fireTableCellUpdated() or another appropriate event; this is typically done in your implementation of setValueAt():

    @Override
    public void setValueAt(Object value, int row, int col) {
        …
        fireTableCellUpdated(row, col);
    }
    

    Complete examples are seen here and here.