javaswingjtablejbuttonabstracttablemodel

JTable filled with files repeats value after model modification (AbstractTableModel)


I am struggling again with JTable and I am very stuck.

The problem is:

I have found many posts with a similar problem but could not sort things out (Try cellRenderer, cellEditor, modify the model and so on). Below I tried to reduce the code to the minimum to make it simple. I have tried many different things but I really do not understand the logic of what is going on (I read the doc entirely, but obviously I am missing something).

I have also tried to do a version with DefaultTableModel, but the problem seems to be independent. Moreover I would like to keep AbstractTableModel because of other classes using it. I think that something is going wrong in the model but I do not know what (tried also different fire*** in the model).

If you see the error and can explain the logic behind it, it would be much appreciated.

Thanks a lot. Here is the code that is, I think, self-explaining:

import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

import javax.swing.BoxLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;


public class FillTableExample extends JFrame {

private JLabel label = new JLabel("File:");
private JButton selectButton = new JButton("Select");
private JPanel labelButtonPane = new JPanel(new FlowLayout(FlowLayout.LEFT));
private Object rowDataTable[][] = {{"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""}};
private String[] columnNames = {"File", "Name"};
private CustomTableModel fileTableModel = new CustomTableModel(rowDataTable, columnNames);
private JTable fileTable = new JTable(fileTableModel);
private JScrollPane scrollPane = new JScrollPane(fileTable);
private FillTable fillTableActionListener = new FillTable(fileTableModel);
private JPanel container = new JPanel();
private JCheckBox changeCol = new JCheckBox("ChangeCol");



public FillTableExample(){


    selectButton.addActionListener(fillTableActionListener);
    labelButtonPane.add(label);
    labelButtonPane.add(selectButton);

    changeCol.addActionListener(new DisplayPane());

    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setLocationRelativeTo(null);
    this.setExtendedState(MAXIMIZED_BOTH);
    this.setMinimumSize(new Dimension(400,400));
    this.setResizable(true);
    container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
    container.add(labelButtonPane);
    container.add(changeCol);
    container.add(scrollPane);
    this.setContentPane(container);
    this.setVisible(true);
}


public class CustomTableModel extends AbstractTableModel {

    private Object rowData[][];
    private String[] columnNames;

    public CustomTableModel(Object data[][], String[] titles){
        rowData = data;
        columnNames = titles;
    }

    public int getColumnCount() {
        return columnNames.length;
    }

    public String getColumnName(int column) {
        return columnNames[column];
    }

    public int getRowCount() {
        return rowData.length;
    }

    public Object getValueAt(int row, int column) {
        return rowData[row][column];
    }

    public Class getColumnClass(int column) {
        return this.rowData[0][column].getClass();
    }


    public int getColumnIndex(String columnName){
        return Arrays.asList(columnNames).indexOf(columnName);
    }

    public void setValueAt(Object value, int row, int column) {
        rowData[row][column] = value;
       // fireTableDataChanged();
    }

    public boolean isCellEditable(int row, int column) {

        if(column == 0 && columnNames[0].equals("Sample Name"))
            return true;
        else
            return (column != 0);
    }
}

class DisplayPane implements ActionListener {


    public void actionPerformed(ActionEvent e){

        final String[] tmpContent1 = {"", "", ""};
        final String[] newColumnNames = {"File", "Name", "Extension"};

        for (int i = 0; i < rowDataTable.length; i++)
                rowDataTable[i] = tmpContent1;
        fileTableModel = new CustomTableModel(rowDataTable, newColumnNames);

        fileTable.setModel(fileTableModel);
        fillTableActionListener.setModel(fileTableModel);
        fileTableModel.fireTableStructureChanged();
        fileTableModel.fireTableDataChanged();
    }
}


class FillTable implements ActionListener {

    private CustomTableModel model;

    public FillTable(CustomTableModel model){

        this.model = model;
    }

    public void actionPerformed(ActionEvent e){

        final JFileChooser fc = new JFileChooser();
        int returnVal;

        fc.setMultiSelectionEnabled(true);
        returnVal = fc.showOpenDialog(FillTableExample.this);

        model.setValueAt("toto", 0, 0);
        //I tried this, but you can see that toto is duplicated when clicking on cell
        //((AbstractTableModel) fileTable.getModel()).fireTableCellUpdated(0, 0);
        model.fireTableDataChanged();
    }

    public void setModel(CustomTableModel model){
        this.model = model;
    }
}


class FileEditor extends DefaultCellEditor {

    public FileEditor(){
        super(new JTextField());
    }
    public Component getTableCellEditorComponent(JTable table, Object value,
              boolean isSelected, int row, int column) {

        JTextField editor = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);

        if(column == 0){
            if(value != "toto")
                editor.setText("");
            else
                editor.setText(value.toString());
        }

        return editor;
    }
}


public static void main(String[] args) {

    FillTableExample example = new FillTableExample();
    example.setVisible(true);
}
}

[****************EDIT]

I have added the command "fileTable.getColumnModel().getColumn(0).setCellEditor(new FileEditor());" in the constructor. Same error

Here is the code using DefaultTableModel (same error):

import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

import javax.swing.BoxLayout;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;


public class FillTableExample2 extends JFrame {

private JLabel label = new JLabel("File:");
private JButton selectButton = new JButton("Select");
private JPanel labelButtonPane = new JPanel(new FlowLayout(FlowLayout.LEFT));
private Object rowDataTable[][] = {{"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""},
        {"", ""}, {"", ""}, {"", ""}, {"", ""}};
private String[] columnNames = {"File", "Name"};
private DefaultTableModel fileTableModel = new DefaultTableModel(rowDataTable, columnNames);
private JTable fileTable = new JTable(fileTableModel);
private JScrollPane scrollPane = new JScrollPane(fileTable);
private FillTable fillTableActionListener = new FillTable(fileTableModel);
private JPanel container = new JPanel();
private JCheckBox changeCol = new JCheckBox("ChangeCol");



public FillTableExample2(){


    selectButton.addActionListener(fillTableActionListener);
    labelButtonPane.add(label);
    labelButtonPane.add(selectButton);

    changeCol.addActionListener(new DisplayPane());
    fileTable.getColumnModel().getColumn(0).setCellEditor(new FileEditor());

    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setLocationRelativeTo(null);
    this.setExtendedState(MAXIMIZED_BOTH);
    this.setMinimumSize(new Dimension(400,400));
    this.setResizable(true);
    container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
    container.add(labelButtonPane);
    container.add(changeCol);
    container.add(scrollPane);
    this.setContentPane(container);
    this.setVisible(true);
}


class DisplayPane implements ActionListener {


    public void actionPerformed(ActionEvent e){
        fileTableModel.addColumn("Extension");
    }
}


class FillTable implements ActionListener {

    private DefaultTableModel model;

    public FillTable(DefaultTableModel model){

        this.model = model;
    }

    public void actionPerformed(ActionEvent e){

        final JFileChooser fc = new JFileChooser();
        int returnVal;

        fc.setMultiSelectionEnabled(true);
        returnVal = fc.showOpenDialog(FillTableExample2.this);

        model.setValueAt("toto", 0, 0);
    }
}


class FileEditor extends DefaultCellEditor {

    public FileEditor(){
        super(new JTextField());
    }
    public Component getTableCellEditorComponent(JTable table, Object value,
              boolean isSelected, int row, int column) {

        JTextField editor = (JTextField) super.getTableCellEditorComponent(table, value, isSelected, row, column);

        if(value != "toto")
            editor.setText("");
        else
            editor.setText(value.toString());

        return editor;
    }
}


public static void main(String[] args) {

    FillTableExample example = new FillTableExample();
    example.setVisible(true);
}
}

Solution

  • Please find the fixed class :

    class DisplayPane implements ActionListener {
    
            public void actionPerformed(ActionEvent e) {
    
                final String[] newColumnNames = { "File", "Name", "Extension" };
    
                for (int i = 0; i < rowDataTable.length; i++){
                    rowDataTable[i] =new String[] { "", "", "" }; // See below
                }
                fileTableModel = new CustomTableModel(rowDataTable, newColumnNames);
    
                fileTable.setModel(fileTableModel);
                fillTableActionListener.setModel(fileTableModel);
                fileTableModel.fireTableStructureChanged();
                fileTableModel.fireTableDataChanged();
            }
        }
    

    The error was caused by the usage of the same String array for every rows. A good practice is to fire event from the model.