我正在为数据库创建一个GUI
项目,有两个类用于GUI's
。连接器类用于连接用户凭据。如果凭据正确,则获取AbstractTableModel
中的所有数据。当程序首先运行时GUI
有一个按钮,我们在其中单击它并获取基础TableModel
中的所有数据。但我面临两个问题。首先在GUI2
课程中,有时它会像这样打开。
有时会显示如下
http://imageshack.com/i/p3gBDt9Ej
我不知道为什么会这样。第二个问题是当我们从表中选择任何行并单击DeleteSelectedRow
按钮时它会删除该行。此按钮在ActionListener
课程中有GUI2
。但我想要的是我删除行时自动更新表。我怎么能这样做?
第一个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);
}
}
答案 0 :(得分:6)
由于数据库访问本质上是异步的,因此您肯定希望在后台检索行以避免阻止event dispatch thread; SwingWorker
使这相对容易。在doInBackground()
,publish()
中间结果的实现中获取行,并将它们添加到process()
实现中的表模型中。显示了一个完整的示例,概述了随之而来的好处here。该示例循环遍历文件,但您可以替换ResultSet
操作。
while (rs.next()) {
//collect row data
publish(rowData);
}
将tableData.add()
推迟到process()
。
关注自定义TableModel
及其包含的SwingWorker
之间的互动,以下complete example会创建一个包含N
行的测试数据库并显示JTable
显示该表的查询结果。特别是,
JDBCModel
扩展AbstractTableModel
。为简单起见,模型data
存储在List<Row>
中,ResultSetMetaData
用于列名称。作为一个更抽象的替代方案,请参阅Apache Commons DbUtils
,它使用Class Literals as Runtime-Type Tokens和ResultSetMetaData
来安全地创建行数据的实例。
JDBCModel
将行检索委托给私人JDBCWorker
;它在从publish()
检索到的每一行上调用ResultSet
;因为process()
在EDT上运行,所以工作人员可以使用fireTableRowsInserted()
优化代表父模型触发的表模型事件的数量。
同样,delete()
的实现应该位于JDBCModel
,而不是GUI;从数据库中成功删除行并从fireTableRowsDeleted()
中删除后,它应data
。
将Thread.sleep()
添加到工作人员的后台循环中,以查看人为增加延迟的效果。
使用setProgress()
和显示here的PropertyChangeListener
来显示进度; <{1}},JOptionPane
可能是多余的。
覆盖done()
以自定义包含getPreferredScrollableViewportSize()
的表格的大小。
避免使用类名,例如JScrollPane
,与常见的API名称冲突。
TableModel