提问者:小点点

AbstractTableModelGUI显示问题


我正在制作一个数据库的GUI项目,有两个类用于GUI的。连接器类用于从用户凭据连接。如果凭据正确,它会从AbstractTableModel中获取所有数据。当程序首先运行时,GUI有一个按钮,我们单击它,它会获取底层TableModel中的所有数据。但是我面临两个问题。首先在GUI2类中,有时它会像这样打开。

有时候会像这样

我不知道为什么会发生这种情况。第二个问题是当我们从表中选择任何一行并单击DeleteSelectedRow按钮时,它会删除该行。这个按钮在GUI2类中有一个ActionListener。但是我想要的是当行被删除时自动更新表。我该怎么做呢?

类首先GUI

public class Gui extends JFrame {
    private static Connector conni;
    private Connection conn = null;
    private JButton bt;
    private JPanel panel;

    public Gui() {
        super("Frame");
        panel = new JPanel();
        bt = new JButton("Connect to Database 'World'");
        panel.add(bt);
        bt.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                conn = conni.Connector();

                if (conn != null) {
                    dispose();
                    new Gui2(conn);

                } else {
                    System.out.println("Return false");

                }

            }

        });
        add(panel);

        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);

    }

}

连接器类

public class Connector {

    private static Connection conn = null;

    public static Connection Connector() {
        String data = "jdbc:mysql://localhost/world";
        String user = "root";
        String pass = "toot";
        try {
            conn = DriverManager.getConnection(data, user, pass);

        } catch (Exception e) {

            JOptionPane.showMessageDialog(null, e.getMessage());

        }
        if (conn != null) {

            System.out.println("Connection Suceess");
            return conn;

        } else {

            return conn;

        }

    }

}

第二个GUI2的类

public class Gui2 extends JFrame {
    private Statement state = null;
    private ResultSet rs = null;

    private JButton bt, delete;
    private JTextField text;
    private JPanel panel;
    private GridBagLayout layout;
    private GridBagConstraints constraints;

    public Gui2(Connection conn) {
        layout = new GridBagLayout();
        constraints = new GridBagConstraints();
        panel = new JPanel();
        panel.setLayout(layout);

        text = new JTextField(15);
        bt = new JButton("Submit Query");
        delete = new JButton("Delete Selected Row");
        constraints.insets = new Insets(5, 2, 5, 10);
        constraints.gridy = 0;// row 0
        constraints.gridx = 0;// column 0
        // TextField add on JPanel with given constraints
        panel.add(text, constraints);
        constraints.gridx++;
        panel.add(delete, constraints);
        constraints.gridx++;
        panel.add(bt, constraints);

        // North BorderLayout
        add(panel, BorderLayout.NORTH);

        try {
            state = conn.createStatement();
            rs = state.executeQuery("select * from city");
        } catch (SQLException e) {

            JOptionPane.showMessageDialog(null, e.getMessage());
        }

        JTable table = new JTable();
        JScrollPane spane = new JScrollPane(table);

        add(spane, BorderLayout.CENTER);

        table.setModel(new TableModel(rs));

        delete.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                int rowIndex = table.getSelectedRow();

                Object columnIndexValue = table.getModel().getValueAt(rowIndex, 0);

                String columnName = table.getModel().getColumnName(0);

                String query = "delete from world.city" + " where " + columnName + "=" + columnIndexValue;

                try {

                    PreparedStatement pre = conn.prepareStatement(query);

                    pre.executeUpdate();

                    JOptionPane.showMessageDialog(null, "Row Deleted Successfully");
                } catch (Exception e1) {
                    JOptionPane.showMessageDialog(null, e1.getMessage());
                }

            }

        });

        setSize(817, 538);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);

    }

}

表模型

public class TableModel extends AbstractTableModel {

    private List ColumnHeader;
    private List tableData;
    private List rowData;

    private int totalcolumn;

    public TableModel(ResultSet rs) {

        try {

            ResultSetMetaData meta = rs.getMetaData();

            totalcolumn = meta.getColumnCount();

            ColumnHeader = new ArrayList(totalcolumn);

            tableData = new ArrayList();

            for (int i = 1; i <= totalcolumn; i++) {
                ColumnHeader.add(meta.getColumnName(i));

            }
        } catch (Exception e) {

            JOptionPane.showMessageDialog(null, e.getMessage());
        }

        SwingWorker<Boolean, List<Object>> worker = new SwingWorker<Boolean, List<Object>>() {

            @Override
            protected Boolean doInBackground() throws Exception {

                while (rs.next()) {

                    rowData = new ArrayList(totalcolumn);
                    for (int i = 1; i <= totalcolumn; i++) {
                        rowData.add(rs.getObject(i));
                    }
                    publish(rowData);


                }

                return true;

            }

            @Override
            protected void process(List chunks) {
                tableData.add(chunks);

            }

            @Override
            protected void done() {
                try {
                    Boolean status = get();
                    JOptionPane.showMessageDialog(null, "Task is DONE");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }

        };

        worker.execute();
    }// constructor end



    @Override
    public int getColumnCount() {

        return ColumnHeader.size();
    }

    public String getColumnName(int columnIndex) {
        return (String) ColumnHeader.get(columnIndex);

    }

    @Override
    public int getRowCount() {

        return tableData.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {

        List rowData2 = (List) tableData.get(rowIndex);

        return rowData2.get(columnIndex);
    }

}

共1个答案

匿名用户

因为数据库访问本质上是异步的,所以您肯定希望在后台检索行以避免阻塞事件调度线程;SwingWorker使这变得相对容易。在您的doIn背景()发布()临时结果的实现中获取行,并将它们添加到您的process()实现中的表模型中。这里显示了一个概述随之而来的好处的完整示例。该示例循环遍历一个文件,但您可以替换您的ResultSet操作。

while (rs.next()) {
    //collect row data
    publish(rowData);
}

tableData. add()延迟到process()的实现中。

关注自定义TableModel与其包含的SwingWorker之间的交互,以下完整示例创建一个具有N行的测试数据库,并显示显示该表查询结果的JTable。特别是,

>

  • JDBCModel扩展AbstractTableModel。为简单起见,模型的数据存储在List中

    JDBCModel将行检索委托给私有JDBCWorker;它对从ResultSet检索到的每一行调用发布();因为process()在EDT上运行,所以Worker可以使用fire TableRowsInserted()来优化它代表父模型触发的表模型事件的数量。

    同样,您的delete()的实现应该驻留在JDBCModel中,而不是GUI;它应该在成功地从数据库中删除该行并从data中删除该行后fire TableRowsDeled()

    Thread.睡眠()添加到worker的后台循环中,以查看人为增加延迟的效果。

    使用setAdvanced()和此处显示的属性更改监听器来显示进度;done()时的JOptionPane可能是多余的。

    覆盖getPreferredScrollableViewportSize()以自定义表的封闭JScrollPane的大小。

    避免类名,例如TableModel,与常见的API名称冲突。

    此处检查了在视图中实现实时过滤的变体。

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.SwingWorker;
    import javax.swing.table.AbstractTableModel;
    
    /**
     * @see https://stackoverflow.com/a/34742409/230513
     * @see https://stackoverflow.com/a/24762078/230513
     */
    public class WorkerTest {
    
        private static final int N = 1_000;
        private static final String URL = "jdbc:h2:mem:test";
        private static final Random r = new Random();
    
        private void display() {
            JFrame f = new JFrame("WorkerTest");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            createTestDatabase(N);
            JDBCModel model = new JDBCModel(getConnection(), "select * from city");
            f.add(new JScrollPane(new JTable(model) {
    
                @Override
                public Dimension getPreferredScrollableViewportSize() {
                    return new Dimension(320, 240);
                }
            }));
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        private static class Row {
            int ID;
            String name;
        }
    
        private static class JDBCModel extends AbstractTableModel {
    
            private final List<Row> data = new ArrayList<>();
            private ResultSet rs = null;
            private ResultSetMetaData meta;
    
            public JDBCModel(Connection conn, String query) {
                try {
                    Statement s = conn.createStatement();
                    rs = s.executeQuery(query);
                    meta = rs.getMetaData();
                    JDBCWorker worker = new JDBCWorker();
                    worker.execute();
                } catch (SQLException e) {
                    e.printStackTrace(System.err);
                }
            }
    
            @Override
            public int getRowCount() {
                return data.size();
            }
    
            @Override
            public int getColumnCount() {
                try {
                    return meta.getColumnCount();
                } catch (SQLException e) {
                    e.printStackTrace(System.err);
                }
                return 0;
            }
    
            @Override
            public Object getValueAt(int rowIndex, int colIndex) {
                Row row = data.get(rowIndex);
                switch (colIndex) {
                    case 0:
                        return row.ID;
                    case 1:
                        return row.name;
                }
                return null;
            }
    
            @Override
            public String getColumnName(int colIndex) {
                try {
                    return meta.getColumnName(colIndex + 1);
                } catch (SQLException e) {
                    e.printStackTrace(System.err);
                }
                return null;
            }
    
            private class JDBCWorker extends SwingWorker<List<Row>, Row> {
    
                @Override
                protected List<Row> doInBackground() {
                    try {
                        while (rs.next()) {
                            Row r = new Row();
                            r.ID = rs.getInt(1);
                            r.name = rs.getString(2);
                            publish(r);
                        }
                    } catch (SQLException e) {
                        e.printStackTrace(System.err);
                    }
                    return data;
                }
    
                @Override
                protected void process(List<Row> chunks) {
                    int n = getRowCount();
                    for (Row row : chunks) {
                        data.add(row);
                    }
                    fireTableRowsInserted(n, n + chunks.size());
                }
            }
        }
    
        private static void createTestDatabase(int n) {
            Connection conn = getConnection();
            try {
                Statement st = conn.createStatement();
                st.execute("create table city(id integer, name varchar2)");
                PreparedStatement ps = conn.prepareStatement(
                    "insert into city values (?, ?)");
                for (int i = 0; i < n; i++) {
                    ps.setInt(1, i);
                    ps.setString(2, (char) ('A' + r.nextInt(26))
                        + String.valueOf(r.nextInt(1_000_000)));
                    ps.execute();
                }
            } catch (SQLException ex) {
                ex.printStackTrace(System.err);
            }
        }
    
        private static Connection getConnection() {
            try {
                return DriverManager.getConnection(URL, "", "");
            } catch (SQLException e) {
                e.printStackTrace(System.err);
            }
            return null;
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new WorkerTest()::display);
        }
    }