Populate JTable from database on login

2019-07-20 14:12发布

问题:

I am populating a JTable from an oracle database connection using JDBC. It currently is working, but I'm trying to make a modification to the code that is breaking it.

Currently it populates the JTable by querying the database when the JTable is created.

I am trying to move this functionality to an ActionListener. Basically, I want to create an empty table, then when a user presses a JButton it should run the sql query and populate and redraw the table. I've tried everything I can think of, and I can't help but think this is a basic one but my logic is failing me.

current implementation:

private void makeTable() {
    Vector columnNames = new Vector();
    Vector data = new Vector();
    String userName = "aUsername";
    String password = "aPassword";
    try {
        DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
        Connection connection = DriverManager.getConnection("redactedDatabaseConnection", userName, password);
        String sql = "select upper(choreName) as Chore, dueDate as due, completedDate as completed, fname as completedby from chore inner join choreCompletion on chore.choreid = chorecompletion.choreid inner join users on users.userID = choreCompletion.completedby";  

        Statement statement = connection.prepareStatement(sql);
        ResultSet rset = statement.executeQuery(sql);
        ResultSetMetaData metaData = rset.getMetaData();
        int columns = metaData.getColumnCount();
        for (int i = 1; i <= columns; i++) {
            columnNames.addElement(metaData.getColumnName(i));
        }
        while (rset.next()) {
            Vector row = new Vector(columns);
            for (int i = 1; i <= columns; i++) {
                row.addElement(rset.getObject(i));
            }
            data.addElement(row);
        }
        rset.close();
        statement.close();
        connection.close();
    } catch (SQLException ex) {ex.printStackTrace();}
    JTable choresTable = new JTable(data, columnNames);
    TableColumn column;
    for (int i = 0; i<choresTable.getColumnCount(); i++) {
        column = choresTable.getColumnModel().getColumn(i);
        column.setMaxWidth(250);
    }
    JScrollPane scrollPane = new JScrollPane(choresTable);
    scrollPane.getViewport().setBackground(new Color(144, 167, 204));
}

EDIT: Current attempt at implementing

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

@SuppressWarnings("unchecked")
public class FillTable extends JFrame
{
private Vector columnNames, data, row;
private Connection connection;
private final String dbUsername = "aUsername";
private final String dbPassword = "aPassword";

private JTable groceryTable;
private TableColumn column;
private JScrollPane pane;
private JPanel panel;

public FillTable()
{
    try {
        DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    } catch(Exception e){
        e.printStackTrace();
    }
    createComponents();
    setSize(800,800);
    setTitle("A filled Table");
}

public static void main(String[] args)
{
    JFrame frame = new FillTable();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setUndecorated(false);
    frame.setLocationRelativeTo(null);
    frame.setResizable(true);
    frame.setVisible(true);
}

class ButtonListener implements ActionListener
{
    public void actionPerformed(ActionEvent e)
    {
        try {
            connection = DriverManager.getConnection("redactedServerInfo", dbUsername, dbPassword);
            String sql = "select upper(name) as Grocery, fname as ordered_by, dateordered as date_ordered from groceries inner join grocerylist on groceries.groceryid=grocerylist.groceryid inner join users on grocerylist.orderedby= users.userid";  
            Statement statement = connection.prepareStatement(sql);
            ResultSet rset = statement.executeQuery(sql);
            ResultSetMetaData metaData = rset.getMetaData();
            int columns = metaData.getColumnCount();
            for (int i=1; i<= columns; i++) {
                columnNames.addElement(metaData.getColumnName(i));
            }
            while (rset.next()) {
                row = new Vector(columns);
                for(int i=1;i<=columns;i++) {
                    row.addElement(rset.getObject(i));
                }
                data.addElement(row);
            }
            rset.close();
            statement.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        for(int i=0;i<groceryTable.getColumnCount(); i++) {
            column = groceryTable.getColumnModel().getColumn(i);
            column.setMaxWidth(250);
        }
        pane.repaint();
        pane.revalidate();
        groceryTable.repaint();
        groceryTable.revalidate();
        panel.repaint();
        panel.revalidate();
        repaint();
        revalidate();
    }
}

private void createComponents()
{
    JButton button = new JButton("Press me");

    ActionListener buttonListener = new ButtonListener();
    button.addActionListener(buttonListener);

    columnNames = new Vector();
    data = new Vector();
    row = new Vector();

    groceryTable = new JTable(data, columnNames);

    pane = new JScrollPane(groceryTable);

    panel = new JPanel();
    panel.add(button);
    panel.add(pane);
    add(panel);
}   

}

回答1:

Create the table with 0 rows as a field.

After

connection.close();

Do

choresTable.setModel(new DefaultTableModel(data, columnNames));

The momentary table creation code with model hence hence can be moved to the general creation code.

Setting the model suffices for redrawing.



回答2:

Basically you want to create and display an empty JTable. The ActionListener should update the table model:

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

//based on 
//https://docs.oracle.com/javase/tutorial/uiswing/examples/components/SimpleTableDemoProject/src/components/SimpleTableDemo.java
public class SimpleTableDemo extends JPanel {

    private JTable table;
    private JButton populate;

    public SimpleTableDemo() {

        makeTable();
        populate = new JButton("Populate");
        populate.addActionListener(e -> populateTable());
        add(populate, BorderLayout.SOUTH);
    }

    private void makeTable() {
        String[] columnNames = {"click button to populate table"};
        Object[][] data = new  Object[][] {};
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        table = new JTable(model);
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);

        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
    }
    private void populateTable() {

        populate.setEnabled(false);
        DefaultTableModel model =  ((DefaultTableModel) table.getModel());
        String[] columnNames = {"First Name", "Last Name"};
        Object[][] data = {
                {"Kathy", "Smith"},
                {"John", "Doe"},
                {"Sue", "Black"},
                {"Jane", "White"},
                {"Joe", "Brown"}
        };
        model.setDataVector(data, columnNames);
    }

    private static void createAndShowGUI() {

        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        SimpleTableDemo newContentPane = new SimpleTableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {

        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}


回答3:

I hope you are familiar with Task, TableView, and ObservableList….

You can use FXCollections.observableList in your controller inside a Task class(you can make a local class in your controller and extend Task) and TableView

Basically use a method that will extract the sql query results and transform those results into a list , than return the list of the items that you want to populate in the formal parameters of FXCollection.observableList……

Bind your TableView columns with the "task" you want to perform i.e, in this case you might want to bind each column with the different fields obtained from the list, now bind your button with the methods in which you call the Thread(task).start method and everything should work.



回答4:

I ended up solving the problem after alot of hours of research and many failed attempts. The introduction of a helper method that returns a table model to fire the update to the table was the key to the solution.

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

@SuppressWarnings("unchecked")
public class FillTable extends JFrame
{
    private Vector columnNames, data, row;
    private Connection connection;
    private final String dbUsername = "aUsername";
    private final String dbPassword = "aPass";

    private JTable groceryTable;
    private TableColumn column;
    private JScrollPane pane;
    private JPanel panel;

    public FillTable()
    {
        createComponents();
        setSize(800,800);
        setTitle("A filled Table");
    }

    public static void main(String[] args)
    {
        JFrame frame = new FillTable();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setUndecorated(false);
        frame.setLocationRelativeTo(null);
        frame.setResizable(true);
        frame.setVisible(true);
    }

class ButtonListener implements ActionListener
{
    public void actionPerformed(ActionEvent e)
    {
        try {
            DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
            connection = DriverManager.getConnection("redactedDBINFO", dbUsername, dbPassword);
            String sql = "select upper(name) as Grocery, fname as ordered_by, dateordered as date_ordered from groceries inner join grocerylist on groceries.groceryid=grocerylist.groceryid inner join users on grocerylist.orderedby= users.userid";  
            Statement statement = connection.prepareStatement(sql);
            ResultSet rset = statement.executeQuery(sql);            
            groceryTable.setModel(updateModel(rset));
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

public DefaultTableModel updateModel(ResultSet rset) throws SQLException
{

    ResultSetMetaData metaData = rset.getMetaData();

    Vector<String> columnNames = new Vector<String>();

    int columnCount = metaData.getColumnCount();
    for (int column = 1; column <= columnCount; column++) {
        columnNames.add(metaData.getColumnName(column));
    }

    Vector<Vector<Object>> data = new Vector<Vector<Object>>();
    while (rset.next()) {
        Vector<Object> vector = new Vector<Object>();
        for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
            vector.add(rset.getObject(columnIndex));
        }
        data.add(vector);
    }
    return new DefaultTableModel(data, columnNames);
}

private void createComponents()
{
    JButton button = new JButton("Press me");
    ActionListener buttonListener = new ButtonListener();
    button.addActionListener(buttonListener);

    groceryTable = new JTable();

    pane = new JScrollPane(groceryTable);

    panel = new JPanel();
    panel.add(button);
    panel.add(pane);
    add(panel);
}   
}


标签: java swing jdbc