如何更新Jtable?

问题描述 投票:0回答:1

我创建了一个 java swing 应用程序,它从数据库中获取数据,并将其显示在 JTable 中。我目前只是想查看数据库中的所有数据。但是当我单击按钮将查询发送到数据库并在jtable上查看获得的数据时,该表没有更新。这是我的代码:

 TableData.java


import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableModel;
import java.awt.*;

public class TableData extends JPanel {
    private JTable table;
    private DefaultTableModel model;
    private final Object Column[] = {"id", "titolo", "autore", "prezzo"};
    TableData(){
        model = new DefaultTableModel();
        table = new JTable(model);
        model.setColumnIdentifiers(Column);
        setLayout(new BorderLayout());
        add(new JScrollPane(table), BorderLayout.CENTER);
    }
    public void updateTable(Object row[]){
        model.addRow(row);
    }
}

 ConnectionDB.java

import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;

public class ConnectionDB {
    private String url = "jdbc:mysql://localhost:4444/database_name";
    private String user = "root";
    private String password = "password";
    TableData tableData = new TableData();
    //id titolo autore prezzo
    public void upload_data(String titolo, String autore, int prezzo){
        try{
            Connection con = DriverManager.getConnection(url, user, password);
            Statement statement = con.createStatement();
            String query = "insert into libri(titolo, autore, prezzo)" +
                           "values ('"+titolo+"','"+autore+"','"+prezzo+"')";
            statement.executeUpdate(query);
            System.out.println("success");
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
    public void get_data(){
        Object row[] = new Object[4];
        try{
            Connection conn = DriverManager.getConnection(url, user, password);
            Statement statement = conn.createStatement();
            ResultSet resultSet = statement.executeQuery("select * from libri");
            while(resultSet.next()){
                for(int i = 1; i<=4; i++){
                    row[i-1] = resultSet.getString(i);
                }
                tableData.updateTable(row);
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}

 PanelForm.java

import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.jar.JarEntry;

public class PanelForm extends JPanel {
    ....somebutton.....
    ConnectionDB conn = new ConnectionDB();

    ....some board....
        buttonVisualizza.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                conn.get_data();
            }
        });
    }
}

这是我的

HomePage.java 

import javax.swing.text.AbstractDocument;
import java.awt.*;

public class HomePage extends JFrame {
    private PanelForm panelForm;
    private TableData tableData;
    HomePage(){
        super("Home");
        setSize(800,500);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocation(200,200);
        setLayout(new BorderLayout());

        panelForm = new PanelForm();
        tableData = new TableData();
        add(panelForm, BorderLayout.LINE_START);
        add(tableData, BorderLayout.CENTER);
        setVisible(true);

    }
}

我已经尝试重新加载模型,这个命令:

 model.fireTableDataChanged();

java database swing jtable
1个回答
0
投票

因此,您立即创建了

TableData
的多个实例....

public class ConnectionDB {
    //...
    TableData tableData = new TableData();

public class HomePage extends JFrame {
    private PanelForm panelForm;
    private TableData tableData;
    HomePage(){
        //..
        tableData = new TableData();

这两个实例彼此之间没有任何关系,因此更新一个实例不会更新另一个实例。

这表明您需要花更多时间研究诸如

之类的概念

首先,您正在使用面向对象的语言,这意味着,您应该尝试将数据更多地描述为“对象”,而不是数组中元素的丢失连接。

让我们从“书”的概念开始......

public interface Book {
    public String getTitle();
    public String getAuthor();
    public int getPrice();
}

我喜欢

interface
,如果您需要将数据源从本地数据库等转移到 Web API,它们可以使您的代码免于在实现级别可能发生的更改。

话虽如此,我们仍然需要一个具体的工具......

public class DefaultBook implements Book {
    private String title;
    private String author;
    private int price;

    public DefaultBook(String title, String author, int price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }
    
    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public String getAuthor() {
        return author;
    }

    @Override
    public int getPrice() {
        return price;
    }
}

我可能也想将记录数据库密钥注入到实现中,但这是您稍后可以解决的详细信息。

接下来,我们来看看

ConnectionDB
...

public class ConnectionDB {
    //...
    public void upload_data(String titolo, String autore, int prezzo){
        try{
            Connection con = DriverManager.getConnection(url, user, password);
            Statement statement = con.createStatement();
            String query = "insert into libri(titolo, autore, prezzo)" +
                           "values ('"+titolo+"','"+autore+"','"+prezzo+"')";
            statement.executeUpdate(query);
            System.out.println("success");
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }

这不仅效率低、速度慢,而且还很危险。

每次创建

Connection
的新实例都很慢,而且您很容易受到 sql 注入 攻击。您也没有关闭任何资源,这可能意味着连接将使它们保持打开状态,从而降低数据库的性能。

首先查看 try-with-resources 语句使用准备好的语句

相反,您应该使用依赖注入来传递对

Connection
的引用。这解决了创建连接的责任类别,允许您创建与您想要的数据库所需的任何连接。

public class ConnectionDB {
    private Connection connection;

    public ConnectionDB(Connection connction) {
        this.connection = connction;
    }

    protected Connection getConnection() {
        return connection;
    }

    public void uploadData(Book book) throws SQLException {
        try(PreparedStatement statement = getConnection().prepareStatement("insert into libri(titolo, autore, prezzo) values (?, ?, ?)")) {
            statement.setString(1, book.getTitle());
            statement.setString(2, book.getAuthor());
            statement.setInt(3, book.getPrice());
            statement.executeUpdate();
            System.out.println("success");
        }
    }

    public List<Book> getData() throws SQLException {
        List<Book> books = new ArrayList<>(32);
        try (Statement statement = getConnection().createStatement()) {
            ResultSet resultSet = statement.executeQuery("select titolo, autore, prezzo from libri");
            while (resultSet.next()) {
                String title = resultSet.getString(1);
                String author = resultSet.getString(2);
                int price = resultSet.getInt(3);
                
                books.add(new DefaultBook(title, author, price));
            }
        }
        return books;
    }
}

您会注意到

getData
返回
List
Book
,这很重要,因为它删除了以前存在的任何实现细节。
ConnectionDB
并不关心您如何使用数据,只关心当您请求时,它会为您返回
List
数据。

另请注意,我不会消耗这些错误。错误管理(除了清理资源之外)不是此类的责任,调用者会想知道何时出现问题。

好吧,让我们进入 UI,说明如何为 UI 的

ConnectionDB
中的数据建模。

我个人会创建一个自定义的

TableModel
,它可以采用
List
Book
并根据需要对其进行建模,例如...

public class BookTableModel extends AbstractTableModel {
    private List<Book> books;
    private String[] columnNames = new String[] {
        "Title", "Author", "Price"
    };

    public BookTableModel(List<Book> books) {
        this.books = books;
    }

    public List<Book> getBooks() {
        return books;
    }
    
    @Override
    public int getRowCount() {
        return getBooks().size();
    }

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

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

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Book book = getBooks().get(rowIndex);
        switch (columnIndex) {
            case 0: return book.getTitle();
            case 1: return book.getAuthor();
            case 2: return book.getPrice();
        }
        return null;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case 0: return String.class;
            case 1: return String.class;
            case 2: return Integer.class;
        }
        return Object.class;
    }        
}

这很重要,因为如果我愿意的话,我可以使用

ListModel
来代替!相同的数据,不同的呈现方式!

public class BookTable extends JPanel {
    private JTable table;
    
    public BookTable(BookTableModel model) {
        setLayout(new BorderLayout());
        table = new JTable(model);
        add(new JScrollPane(table));
    }

    protected JTable getTable() {
        return table;
    }

    public BookTableModel getModel() {
        return (BookTableModel) getTable().getModel();
    }

    public void setModel(BookTableModel model) {
        getTable().setModel(model);
    }
}

现在,除非我的 UI 足够复杂,否则我可能不会将表管理分离到单独的类中,相反,我可能会做类似的事情......

public class BookPane extends JPanel {
    private ConnectionDB connectionDB;
    
    private JTable bookTable;

    public BookPane(ConnectionDB connectionDB) {
        this.connectionDB = connectionDB;
        setLayout(new BorderLayout());
        
        // You could add a empty constructor to the
        // BookTableModel to make this a bit easier
        bookTable = new JTable(new BookTableModel(new ArrayList<>()));
        
        add(new JScrollPane(bookTable));
        
        JButton loadButton = new JButton("Load");
        loadButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    List<Book> data = getConnectionDB().getData();
                    // You could just replace the `List` managed by
                    // BookTableModel, but this is just simpler
                    getBookTable().setModel(new BookTableModel(data));
                } catch (SQLException ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(BookPane.this, "Failed to load data", "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
        });
    }

    public ConnectionDB getConnectionDB() {
        return connectionDB;
    }

    protected JTable getBookTable() {
        return bookTable;
    }               
}

那么,这一切是如何联系在一起的呢?嗯,也许类似...

Connection connection = ...; // Create an instance of a Connection for your database
ConnectionDB connectionDB = new ConnectionDB(connection);

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        JFrame frame = new JFrame();
        frame.add(new BookPane(connectionDB));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
});
© www.soinside.com 2019 - 2024. All rights reserved.