Populating jTable using database data

John Vasiliou picture John Vasiliou · Feb 28, 2013 · Viewed 12.2k times · Source

I am trying to populate a Netbeans GUI-builder jTable using my Derby database data.

I am using the following code, in my Account.java class:

public DefaultTableModel getData() {
    try {
        String stmt = "SELECT * FROM APP.DATAVAULT";
        PreparedStatement ps = Main.getPreparedStatement(stmt);
        ResultSet rs = ps.executeQuery();
        ResultSetMetaData md = rs.getMetaData();
        int columnCount = md.getColumnCount();
        Vector columns = new Vector(columnCount);
        //store column names  
        for (int i = 1; i <= columnCount; i++) {
            columns.add(md.getColumnName(i));
        }

        Vector data = new Vector();
        Vector row;
        while (rs.next()) {

            row = new Vector(columnCount);
            for (int i = 1; i <= columnCount; i++) {
                row.add(rs.getString(i));
            }
            data.add(row);

            //Debugging                
        }

        // List.setModel(tableModel);

        ps.close();
        rs.close();
    } catch (SQLException e) {
        System.out.println(e.getMessage());
    }
    DefaultTableModel tableModel = new DefaultTableModel(data, columns);
    return tableModel;
}

Ideally, I want to be able to return the tableModel with the parameters data and columns inside, as I understand doing this method within my GUI is bad practice. All tutorials online do not show how to send the data across to another class, they just do the database code within the GUI classes.

I have an error where it cannot see data and columns because they are declared and used in an unreachable part of my method. After I've done this, I need to find a way of getting this across to my GUI class and setting the model for my jTable which was made by Netbeans GUI builder.

I have been searching this website for answers and I have tried many solutions. However, I never seem to get anything to work due to the way I have coded my system. I have also tried other websites such as:

http://tips4java.wordpress.com/2009/03/12/table-from-database/

http://chang.advits.com/populate-data-from-database-into-jtable-in-netbeans < this would have been ideal but it did not work. I followed it to a tee!

and have looked at the Javadocs for jTable, DefaultTableModel and ResultSetTableModel - I have by no means not tried doing this myself by learning etc...

How can I go about doing this with the way I have modelled my system? Also, anyway of fixing my method or should I scrap it altogether?

Answer

MadProgrammer picture MadProgrammer · Feb 28, 2013

So, you need some way to "tell" the table that the model has been loaded. You could use a listener call back mechanism, but it might be easier to use a SwingWorker instead.

This will allow you to make a call to the database in a background thread and when it's finished, update the UI from within the EDT.

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Vector;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import sun.applet.Main;

public class DataLoadWorker extends SwingWorker<TableModel, TableModel> {

    private final JTable table;

    public DataLoadWorker(JTable table) {
        this.table = table;
    }

    @Override
    protected TableModel doInBackground() throws Exception {
        Vector data = new Vector();
        Vector columns = new Vector();
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            String stmt = "SELECT * FROM APP.DATAVAULT";
            ps = Main.getPreparedStatement(stmt);
            rs = ps.executeQuery();
            ResultSetMetaData md = rs.getMetaData();
            int columnCount = md.getColumnCount();
            //store column names  
            for (int i = 1; i <= columnCount; i++) {
                columns.add(md.getColumnName(i));
            }

            columns.ensureCapacity(columnCount);

            Vector row;
            while (rs.next()) {

                row = new Vector(columnCount);
                for (int i = 1; i <= columnCount; i++) {
                    row.add(rs.getString(i));
                }
                data.add(row);

                //Debugging                
            }

            // List.setModel(tableModel);

        } finally {
            try {
                ps.close();
            } catch (Exception e) {
            }
            try {
                rs.close();
            } catch (Exception e) {
            }
        }

        DefaultTableModel tableModel = new DefaultTableModel(data, columns);
        return tableModel;
    }

    @Override
    protected void done() {
        try {
            TableModel model = get();
            table.setModel(model);
        } catch (InterruptedException | ExecutionException ex) {
            ex.printStackTrace();
        }
    }
}

You're example won't work either.

The Vectors columns and data are declared withing the context of the try-catch, which means they won't be visible to the remainder of the method, so DefaultTableModel tableModel = new DefaultTableModel(data, columns); won't compile.

You should be, at the very least, dumping the stack trace of any exceptions, it will help you find where the actually error is, so instead of System.out.println(e.getMessage());, you should use e.printStackTrace();. A better solution is to use the Logger either from the JDK or a third party logger like log4j.

You are also resources, that is, if you open, you should close it. While you do call ps.close() and rs.close(), if, for what ever reason, an exception occurs, they will not be called, leaving resources open.

Add these to the finally block of your try-catch to ensure that they are closed and make all best efforts to close them.