AbstractTableModel GUI显示问题 [英] AbstractTableModel GUI display issue

查看:81
本文介绍了AbstractTableModel GUI显示问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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







有时显示如下



  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
* /
公共类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);
}

私有静态类行{
int ID;
字符串名称;
}

私有静态类JDBCModel扩展AbstractTableModel {

私有最终列表<行> 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);
}
返回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;
}
返回null;
}

@Override
public String getColumnName(int colIndex){
try {
return meta.getColumnName(colIndex + 1);
} catch(SQLException e){
e.printStackTrace(System.err);
}
返回null;
}

私有类JDBCWorker扩展了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);
}
返回数据;
}

@Override
protected void process(List< Row> chunks){
int n = getRowCount();
for(行行:块){
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(
插入城市值(?,?));
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);
}
返回null;
}

public static void main(String [] args){
EventQueue.invokeLater(new WorkerTest():: display);
}
}


I'm making a GUI Project for database there are two classes which are for 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. When program run first GUI has a button in which we click it and it fetch all data in underlying TableModel. But i'm facing two problems. First in GUI2 class, sometimes it open like this.


and sometimes it show like this

http://imageshack.com/i/p3gBDt9Ej

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. This button has a ActionListener in GUI2 class. But what i want is i automatic update the table when row has been deleted. How can i do that?

class for first 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

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

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. Fetch rows in your implementation of doInBackground(), publish() interim results, and add them to the table model in your implementation of 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.

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

Defer tableData.add() to your implementation of 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. In particular,

  • JDBCModel extends AbstractTableModel. For simplicity, the model's data is stored in a List<Row>, and ResultSetMetaData is used for the column names. 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.

  • JDBCModel delegates row retrieval to a private JDBCWorker; it invokes publish() on each row retrieved from the ResultSet; 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().

  • Similarly, your implementation of delete() should reside in JDBCModel, not the GUI; it should fireTableRowsDeleted() after the row is successfully deleted from the database and removed from data.

  • Add Thread.sleep() to the worker's background loop to see the effect of artificially increasing latency.

  • Use setProgress() and a PropertyChangeListener, shown here, to display progress; a JOptionPane when done() may be superfluous.

  • Override getPreferredScrollableViewportSize() to customize the size of the table's enclosing JScrollPane.

  • Avoid class names, e.g. TableModel, that collide with common API names.

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

这篇关于AbstractTableModel GUI显示问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆