2

I have read so many questions on this website concerning this problem and I cannot find why it is still not working.

The Problem:

I made a JTable to be displayed inside a JScrollPane. The JTable is constructed as follows:

table = new JTable(new DataTableModel());   

As you can see, I use a custom AbstractDataModel called DataTableModel. Now, when I display this the checkboxes appear, but they are not able to be selected. They are editable as you can see below. Here is the pertinent code in the DataTableModel class: (note that my column for check boxes is the first column, at index 0, and that my data in my array at this column is "null"). For some

public class DataTableModel extends AbstractTableModel
{
    private String[][] data;
    private String[] header =
    { "", "KB Name", "fpGUID" };

    public DataTableModel() throws SQLException
    {
        // ========= CONNECTS TO DB AND PULLS RESULTS ==========

        // GETS RESULTS SET CALLED "rs"

        // populate data array
        int counter = 0;
        while (rs.next())
        {
            //data[counter][0] = "sfsdfsdfs ";
            data[counter][1] = (String) rs.getObject(2);
            data[counter][2] = (String) rs.getObject(4);

            counter++;
        }
        // =====================================================

    }

@Override
public String getValueAt(int rowIndex, int columnIndex)
{
    return data[rowIndex][columnIndex];
}

public boolean isCellEditable(int row, int col)
{
    return col == 0;
}

public Class getColumnClass(int column)
{
    if (column == 0)
    {
        return Boolean.class;
    } else
    {
        return String.class;
    }
}

So, it seems my getColumnClass() method is fine, so what is the problem? Could it be something with my "data" which I store the data for the table. Here is the data array:

Sam
  • 7,252
  • 16
  • 46
  • 65
Richie Episcopo
  • 383
  • 1
  • 3
  • 15
  • 3
    This doesn't look right: `String getValueAt(...)`. This should return an Object, not a String, and in particular, if the columnIndex is 0, it should return a `Boolean` to agree with your `getColumnClass` and with your need to display an editable JCheckBox. – Hovercraft Full Of Eels Jul 11 '13 at 22:21
  • Oh, it should return an Object? And I tried to assign column 0 of the data array to false but I get an error because my data array is of type String. Should I make the data type if the data array to Object (I think I already tried this but was getting an error..). – Richie Episcopo Jul 11 '13 at 23:15
  • You need to look at the API for [TableModel](http://docs.oracle.com/javase/7/docs/api/javax/swing/table/TableModel.html). What is the signature for the `getValueAt(...)` method? The API will tell you. As for your errors, well, you'll need to fix them, but I am 100% sure that the data of column 0 *must* be `Boolean`. – Hovercraft Full Of Eels Jul 11 '13 at 23:18
  • For [example](http://stackoverflow.com/a/13919878/230513). – trashgod Jul 11 '13 at 23:29
  • Thank you all for your input, greatly appreciated! – Richie Episcopo Jul 12 '13 at 13:54

1 Answers1

4

There are a number of things that jump out...

  • (As has already begin pointed out) getValueAt appears to be declared wrong. It should be returning Object. Think about it for a second. Your expectation is that the first column will be boolean, so how can you return String from this method...which leads to...
  • Your data array is an array of String...where, again, the expectation is that the first value should be boolean. Now you can actually keep this, but you will need to translate the value to boolean from the getValueAt method and back again for the setValueAt method...which leads to...
  • You've not implemented setValueAt, so there is no way that the changes to the cell value can be stored
  • You're also not implementing getRowCount, which is required, getColumnCount, which is required and you should implement getColumnName, since you actually have some.

enter image description here

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.sql.SQLException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;

public class TestTableModel02 {

    public static void main(String[] args) {
        new TestTableModel02();
    }

    public TestTableModel02() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(new JTable(new DataTableModel())));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class DataTableModel extends AbstractTableModel {

        private Object[][] data;
        private String[] header = {"", "KB Name", "fpGUID"};

        public DataTableModel() {//throws SQLException {
            // ========= CONNECTS TO DB AND PULLS RESULTS ==========

            // GETS RESULTS SET CALLED "rs"

            // populate data array
//            int counter = 0;
//            while (rs.next()) {
//                //data[counter][0] = "sfsdfsdfs ";
//                data[counter][1] = (String) rs.getObject(2);
//                data[counter][2] = (String) rs.getObject(4);
//
//                counter++;
//            }
            // =====================================================

            data = new Object[4][3];
            data[0] = new Object[]{false, "Help", "1234"};
            data[1] = new Object[]{false, "On fire", "5648"};
            data[2] = new Object[]{false, "Drowning", "9012"};
            data[3] = new Object[]{false, "Micky Mouse", "3456"};
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            return data[rowIndex][columnIndex];
        }

        @Override
        public boolean isCellEditable(int row, int col) {
            return col == 0;
        }

        @Override
        public Class getColumnClass(int column) {
            if (column == 0) {
                return Boolean.class;
            } else {
                return String.class;
            }
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            if (columnIndex == 0) {
                if (aValue instanceof Boolean) {
                    data[rowIndex][columnIndex] = (Boolean)aValue;
                    fireTableCellUpdated(rowIndex, columnIndex);
                }
            }
        }

        @Override
        public int getRowCount() {
            return data.length;
        }

        @Override
        public int getColumnCount() {
            return header.length;
        }

        @Override
        public String getColumnName(int column) {
            return header[column];
        }
    }
}

Now, there are ways you can get around the whole "first column must be boolean" issue, but to be frank, it's much less code to do it this way.

I would also, strongly, recommend that you take a look at SwingWorker and do all your data loading using it, otherwise you may find that your UI comes to a grinding halt while the data is begin loaded, which is generally rather unpleasant.

Take a look at...

For more details

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Inside the `setValueAt()` method of `DataTableModel` class, isn't the programmer suppose to call `fireTableCellUpdated(row, col);` ? – nIcE cOw Jul 12 '13 at 08:30
  • @nIcEcOw cells, rows, you get the same effect :P – MadProgrammer Jul 12 '13 at 09:43
  • LOL :-), actually, just started reading about `JTable` now a days, never tried it before. But aren't we just changing a `single Cell` while clicking on a `JCheckBox` acting as a renderer, as against the whole `Row`, though +1 for this example :-) – nIcE cOw Jul 12 '13 at 09:47
  • 1
    Yes, it would be more efficient to use cellUpdate as the table only needs to update a single cell and re-render the entire row – MadProgrammer Jul 12 '13 at 09:49
  • Thankyou for the profound information, mate, surely will help me as I move along reading more about `JTable` and KEEP SMILING :-) – nIcE cOw Jul 12 '13 at 09:53
  • Great! These were my problems! Thank you very much for such a complete answer (by the way I did have `getRowCount()` `getColumnCount()` and `getColumnName()` implemented I just didn't post it, I should have though). – Richie Episcopo Jul 12 '13 at 13:53