javaswingjcheckboxtablecellrendererabstracttablemodel

Problem with JCheckbox in my table that extends AbstractTableModel


The FileSystemModel class gives me a list of files from the system. I want to use the checkbox to select files to download, but I can not edit this checkbox. I am asking for a hint as to what I am doing wrong.

MyTableModel.java

public class MyTableModel extends AbstractTableModel{
private File dir;
private String[] filenames;
private static final long serialVersionUID = -2929662905556163705L;

public DownloadTableModel(File dir) {
    this.dir = dir;
    this.filenames = dir.list();
}

private ResourceBundle resourceBundle = ResourceBundle.getBundle("MessageBundle", Locale.forLanguageTag("pl"));

protected String[] columns = new String[] {"fileName","fileSize","checked","progress"};

@SuppressWarnings("rawtypes")

protected Class[] columnClasses = {FileSystemModel.class , Long.class, JCheckBox.class, JProgressBar.class};

The FileSystemModel class gives me a list of files from the system.

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

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

public String getColumnName(int col) {
    return columns[col].toString();
}

public Class getColumnClass(int c) {
    switch (c) {
    case 0:
        return String.class;
    case 1:
        return Long.class;
    case 2:
        return Boolean.class;
    case 3:
        return Float.class;
    default:
        return null;
    }
}

public Object getValueAt(int row, int col) {
    File f = new File(dir, filenames[row]);
    
    switch (col) {
    case 0:
        return filenames[row];
    case 1:
        return new Long(f.length());
    case 2:
        return new Boolean(false);
    case 3:
        return new Float(50);
    default:
        return null;
    }
}

public boolean isCellEditable(int row, int col) {
    switch (col) {
    case 0:
        return false;
    case 1:
        return false;
    case 2:
        return true;
    case 3:
        return false;
    default:
        return false;
    }
}   

public void setValueAt(String aValue, int row, int column) {
      if ( column == 2) {
        filenames[row] = aValue;
        fireTableCellUpdated(row, column);
        System.out.println(aValue + " " + row);
      }
    }

}

CheckBoxRenderer.java

public class CheckBoxRenderer extends JCheckBox implements TableCellRenderer {

private static final long serialVersionUID = -1892085041343659845L;

private static final Border NO_FOCUS = BorderFactory.createEmptyBorder(1, 1, 1, 1);

public CheckBoxRenderer() {
    super();
    setHorizontalAlignment(JCheckBox.CENTER);
    setBorderPainted(true);
    setOpaque(true);
}

public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {

    Color alternate = UIManager.getColor("Table.alternateRowColor");
    Color normal = new Color(table.getBackground().getRGB());

    if (isSelected) {
        setForeground(table.getSelectionForeground());
        setBackground(table.getSelectionBackground());
    } else {
        setForeground(table.getForeground());
        setBackground(alternate != null && row % 2 == 0 ? normal : alternate);
    }
    
    setEnabled(table.isCellEditable(row, column));
    setSelected(value != null && (Boolean) value);

    if (hasFocus) {
        setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
    } else {
        setBorder(NO_FOCUS);
    }

    return this;
}
}

MainGUI

In the main gui I add it to the panel

fileDir = new File(System.getProperty("user.dir"));
    myTableModel = new MyTableModel(fileDir);
    jTable = new JTable(downloadModel);

enter image description here


Solution

  • I don't see where you store the data in the TableModel. All you have is an Array of filenames. You don't store the Boolean value for each row to know if it is selected or not.

    File f = new File(dir, filenames[row]);
    

    In your getValueAte(...) method you continually create a new File object. This is not very efficient and the getValueAt(...) method is constantly invoked by the table. For example every time you highlight a row you need to repaint the previous row as unselected and then the current row as selected.

    So the getValueAt(...) method should be as efficient as possible.

    So what I would do:

    1. create a custom TableModel that contains all the values you want to display in your table, plus the Boolean value for the check box.

    2. forget about the custom renderer/editor for now. First get the logic working using the default renderer/editor for the Boolean column. Prove that the basic logic works. Then if you think you need to make the rendering fancier you create a custom renderer. Then if you have problems you know where the problems are.

    You can check out Row Table Model for a step by step example of creating a TableModel based on a custom object.