0

I have a jTable displaying a simple two column sql table's data and allowing a user to maintain the list. This is my first java program. Have that working such that user can edit the list of data and press save to update. I get the sql data to the jTable's DefaultTableModel from this line of code:

paCutAboveTable.SetTableModel((DefaultTableModel) DbUtils.resultSetToTableModel(rs));

I'm guessing DBUtils and resultSets are familiar to people here. I want to add a CheckBox to each row. Looking here and elsewhere I kept seeing to subclass DefaultTableModel in order to override a method thus:

/*

  * JTable uses this method to determine the default renderer/
  * editor for each cell.  If we didn't implement this method,
  * then the last column would contain text ("true"/"false"),
  * rather than a check box.
  */

 public Class getColumnClass(int c) {

     return getValueAt(0, c).getClass();
   }

However I can't figure how to get the output of DefaultTableModel from resultSetToTableModel method to my subclass - the statement shown doesn't compile if the SetTableModel method is changed to accept the subclass as its parameter. Is there an easy way I'm missing?

Louis
  • 3,592
  • 2
  • 10
  • 18
Matthew
  • 3
  • 2
  • Please read about [renderer and editor concept](https://docs.oracle.com/javase/tutorial/uiswing/components/table.html#editrender). – Sergiy Medvynskyy Apr 11 '19 at 08:33
  • thanks for your fast input Sergiy. Reading that I see "Remember that if you let a table create its own model, it uses Object as the type of every column. To specify more precise column types, the table model must define the getColumnClass method appropriately, as demonstrated by TableDemo.java." Does this not get me back to my problem? – Matthew Apr 11 '19 at 08:59
  • I think I'm going to change tack and make my own code to extract the data from resultSet (to my subclass) as per this [link](https://stackoverflow.com/questions/10620448/most-simple-code-to-populate-jtable-from-resultset) – Matthew Apr 11 '19 at 10:45
  • When you want to get a checkbox, you simply need to retern `Boolean.class` for the column in `getColumnClass` method. But it could also be made by a custom renderer/editor. I'll try to provide an example. – Sergiy Medvynskyy Apr 11 '19 at 11:19
  • [Here](https://stackoverflow.com/questions/7391877/how-to-add-checkboxes-to-jtable-swing) is an example. – Sergiy Medvynskyy Apr 11 '19 at 11:54
  • @Matthew, `make my own code to extract the data from resultSet (to my subclass) as per this link` - its always a good idea to be in full control of the data found in the ResultSet and create your own TableModel, however none of those examples show how to override the getColumnClass(...) method to the data is displayed properly and not all treated like a String. – camickr Apr 11 '19 at 14:35

1 Answers1

2

Here is an example that shows how to read the data from the ResultSet and implement the getColumnClass(...) method in your own custom DefaultTableModel:

import java.awt.*;
import java.sql.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableFromDatabase extends JFrame
{
    public TableFromDatabase()
    {
        Vector<Object> columnNames = new Vector<Object>();
        Vector<Object> data = new Vector<Object>();

        try
        {
            //  Connect to an Access Database

            String driver = "sun.jdbc.odbc.JdbcOdbcDriver";
//            String url = "jdbc:odbc:???";  // if using ODBC Data Source name
            String url =
                "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=c:/directory/???.mdb";
            String userid = "";
            String password = "";

            Class.forName( driver );
            Connection connection = DriverManager.getConnection( url, userid, password );

            //  Read data from a table

            String sql = "Select * from ???";
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery( sql );
            ResultSetMetaData md = rs.getMetaData();
            int columns = md.getColumnCount();

            //  Get column names

            for (int i = 1; i <= columns; i++)
            {
                columnNames.addElement( md.getColumnLabel(i) );
            }

            //  Get row data

            while (rs.next())
            {
                Vector<Object> row = new Vector<Object>(columns);

                for (int i = 1; i <= columns; i++)
                {
                    row.addElement( rs.getObject(i) );
                }

                data.addElement( row );
            }

            rs.close();
            stmt.close();
            connection.close();
        }
        catch(Exception e)
        {
            System.out.println( e );
        }

        //  Create table with database data

        DefaultTableModel model = new DefaultTableModel(data, columnNames)
        {
            @Override
            public Class getColumnClass(int column)
            {
                for (int row = 0; row < getRowCount(); row++)
                {
                    Object o = getValueAt(row, column);

                    if (o != null)
                    {
                        return o.getClass();
                    }
                }

                return Object.class;
            }
        };

        JTable table = new JTable( model );
        JScrollPane scrollPane = new JScrollPane( table );
        add( scrollPane );

        JPanel buttonPanel = new JPanel();
        add( buttonPanel, BorderLayout.SOUTH );
    }

    public static void main(String[] args)
    {
        TableFromDatabase frame = new TableFromDatabase();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setVisible(true);
    }
}

By overriding the getColumnClass(...) method you will now see number formatted right aligned and if you ever need to sort the data it will work properly since the column will be sorted based on a numeric value not a String value.

I want to add a CheckBox to each row.

So now you have two options:

  1. Modify the above code so that the "columnNames" Vector contains another header name for the check box column and add Boolean.FALSE to each "row" Vector as you iterate through the ResultSet.

  2. Use the above TableModel as is (or use the DbUtils TableModel) and then create a wrapper TableModel that will add a check box column to any existing TableModel. Check out: How to add checkbox in Jtable populated using rs2xml for an example of this approach.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • Thanks camickr. You have pointed out a significant lack of understanding I had. I thought to override the method I had to do it via a subclass - ie: extend the DefaultTableModel for my own class. I will give it all a go to get my checkbox working. – Matthew Apr 12 '19 at 02:14
  • @Matthew, My example uses an "anonymous inner class". – camickr Apr 12 '19 at 03:06
  • Thanks camickr. Reading up on that I see I would need to subclass in order to override except with your sort of code which is just for one off "local" use. Thanks for peoples help. – Matthew Apr 12 '19 at 06:05
  • Hi camickr I clicked the tick hope that was the checkmark – Matthew Apr 14 '19 at 08:01