简体   繁体   English

AbstractTableModel GUI 显示问题

[英]AbstractTableModel GUI display issue

I'm making a GUI Project for database there are two classes which are for GUI's .我正在为数据库制作一个GUI项目,有两个类用于GUI's . And connector class is used to connect from user credentials.连接器类用于从用户凭据进行连接。 If credentials are correct than it fetch all data in the from of AbstractTableModel .如果凭据正确,则从AbstractTableModel获取所有数据。 When program run first GUI has a button in which we click it and it fetch all data in underlying TableModel .当程序第一次运行时, GUI有一个按钮,我们点击它,它会获取底层TableModel所有数据。 But i'm facing two problems.但我面临两个问题。 First in GUI2 class, sometimes it open like this.首先在GUI2类中,有时它会像这样打开。

在此处输入图片说明

and sometimes it show like this有时它是这样显示的

在此处输入图片说明

I don't know why it's happening.我不知道为什么会这样。 And second problem is when we select any row from table and click on DeleteSelectedRow button it delete the row.第二个问题是当我们从表中选择任何行并单击DeleteSelectedRow按钮时,它会删除该行。 This button has a ActionListener in GUI2 class.这个按钮在GUI2类中有一个ActionListener But what i want is i automatic update the table when row has been deleted.但我想要的是当行被删除时我自动更新表。 How can i do that?我怎样才能做到这一点?

class for first GUI第一个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);

    }

}

Connector class连接器类

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;

        }

    }

}

class for second GUI2第二个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 Class 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);
    }

}

Because database access is inherently asynchronous, you'll surely want to retrieve rows in the background to avoid blocking the event dispatch thread ;因为数据库访问本质上是异步的,所以您肯定希望在后台检索行以避免阻塞事件调度线程 SwingWorker makes this relatively easy. SwingWorker使这相对容易。 Fetch rows in your implementation of doInBackground() , publish() interim results, and add them to the table model in your implementation of process() .doInBackground()实现中获取行, publish()中间结果,并将它们添加到process()实现中的表模型中。 A complete example that outlines the attendant benefits is shown here .此处显示了概述附带好处的完整示例。 The example loops through a file, but you can substitute your ResultSet operations.该示例循环遍历一个文件,但您可以替换您的ResultSet操作。

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

Defer tableData.add() to your implementation of process() .tableData.add()推迟到process()

Focusing on the interaction between the custom TableModel and its contained SwingWorker , the following complete example creates a test database having N rows and displays a JTable showing the results of a query of that table.关注自定义TableModel与其包含的SwingWorker之间的交互,以下完整示例创建一个具有N行的测试数据库并显示一个JTable显示了对该表的查询结果。 In particular,特别是,

  • JDBCModel extends AbstractTableModel . JDBCModel扩展了AbstractTableModel For simplicity, the model's data is stored in a List<Row> , and ResultSetMetaData is used for the column names.为简单起见,模型的data存储在List<Row> ,而ResultSetMetaData用于列名。 As a more abstract alternative, see Apache Commons DbUtils , which uses Class Literals as Runtime-Type Tokens and ResultSetMetaData to safely create instances of row data.作为更抽象的替代方案,请参阅 Apache Commons DbUtils ,它使用类文字作为运行时类型标记ResultSetMetaData来安全地创建行数据的实例。

  • JDBCModel delegates row retrieval to a private JDBCWorker ; JDBCModel将行检索委托给私有的JDBCWorker it invokes publish() on each row retrieved from the ResultSet ;它对从ResultSet检索到的每一行调用publish() because process() runs on the EDT, the worker can optimize the number of table model events that it fires on behalf of the parent model using fireTableRowsInserted() .因为process()在 EDT 上运行,所以工作器可以使用fireTableRowsInserted()优化代表父模型触发的表模型事件的数量。

  • Similarly, your implementation of delete() should reside in JDBCModel , not the GUI;同样,您的delete()应该驻留在JDBCModel ,而不是 GUI 中; it should fireTableRowsDeleted() after the row is successfully deleted from the database and removed from data .在成功从数据库中删除行并从data删除后,它应该fireTableRowsDeleted()

  • Add Thread.sleep() to the worker's background loop to see the effect of artificially increasing latency.Thread.sleep()添加到 worker 的后台循环中,查看人为增加延迟的效果。

  • Use setProgress() and a PropertyChangeListener , shown here , to display progress;使用setProgress()和一个PropertyChangeListener所示,这里,对显示进展; a JOptionPane when done() may be superfluous. done()时的JOptionPane可能是多余的。

  • Override getPreferredScrollableViewportSize() to customize the size of the table's enclosing JScrollPane .覆盖getPreferredScrollableViewportSize()以自定义表的封闭JScrollPane的大小。

  • Avoid class names, eg TableModel , that collide with common API names.避免与通用 API 名称冲突的类名称,例如TableModel

  • A variation that implements live filtering in the view is examined here .此处检查了视图中实现实时过滤的变体。

图片

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM