AbstractTableModel上的GUI显示问题AbstractTableModel上的GUI

2019-06-17 09:55发布

我正在做一个GUI数据库项目有两类这对GUI's 。 和连接器类是用于从用户凭据连接。 如果凭据是正确的比它从获取的所有数据AbstractTableModel 。 当程序运行第一GUI有一个按钮,我们点击它,它在底层获取所有数据TableModel 。 但我面临两个问题。 首先在GUI2类,有时打开这个样子。


有时它显示出这样的

http://imageshack.com/i/p3gBDt9Ej

我不知道为什么它的发生。 而第二个问题是,当我们选择表中的任何行,点击DeleteSelectedRow按钮,它删除行。 此按钮有一个ActionListenerGUI2类。 但是,我想是我自动更新表时行已被删除。 我怎样才能做到这一点?

类第一个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);

    }

}

Tablemodel

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);
    }

}

Answer 1:

由于数据库访问本质上是异步的,你肯定会想在后台避免阻塞检索行事件调度线程 ; SwingWorker使这个相对容易。 读取行,在执行doInBackground() publish()中期业绩,并在你的实现添加到表模型process() 概述本服务员好处一个完整的例子显示在这里 。 该示例遍历一个文件,但你可以替换你ResultSet操作。

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

推迟tableData.add()你执行的process()

着眼于自定义之间的相互作用TableModel和其所含SwingWorker ,下面的完整实例创建具有测试数据库N行并显示JTable示出该表的查询的结果。 特别是,

  • JDBCModel扩展AbstractTableModel 。 为简单起见,该模型的data存储在一个List<Row> ,和ResultSetMetaData用于列名。 作为更抽象的替代方案中,见阿帕奇百科全书DbUtils ,其使用类常量作为运行时类型令牌ResultSetMetaData安全地创建行数据的实例。

  • JDBCModel代表行检索到的私人JDBCWorker ; 它调用publish()从检索到的每一行ResultSet ; 因为process()的运行EDT,工人可以优化其使用代表父模型的触发台模型事件的数量fireTableRowsInserted()

  • 同样的,你的执行delete()应位于JDBCModel ,没有GUI; 它应该fireTableRowsDeleted()后,该行已成功从数据库中删除,并从删除data

  • 加入Thread.sleep()来工人的背景环路看到人为地增加延迟的影响。

  • 使用setProgress()和一个PropertyChangeListener所示, 这里 ,要显示的进展; 一个JOptionPanedone()可能是多余的。

  • 覆盖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);
    }
}


文章来源: AbstractTableModel GUI display issue