usar sintaxis setvalueat setrowsorter setmodel como addrow java swing jdbc jtable abstracttablemodel

java - sintaxis - Problema de visualización de la GUI de AbstractTableModel



setrowsorter java (1)

Debido a que el acceso a la base de datos es intrínsecamente asíncrono, seguramente querrá recuperar filas en segundo plano para evitar el bloqueo de la cadena de distribución de eventos ; SwingWorker hace relativamente fácil. Obtenga filas en su implementación de doInBackground() , publish() resultados provisionales y agréguelos al modelo de tabla en su implementación de process() . Aquí se muestra un ejemplo completo que describe los beneficios correspondientes. El ejemplo recorre un archivo, pero puede sustituir las operaciones de ResultSet .

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

tableData.add() a su implementación de process() .

Centrándose en la interacción entre el TableModel personalizado y su SwingWorker contenido, el siguiente ejemplo completo crea una base de datos de prueba con N filas y muestra una JTable muestra los resultados de una consulta de esa tabla. En particular,

  • JDBCModel extends AbstractTableModel . Para simplificar, los data del modelo se almacenan en una List<Row> , y ResultSetMetaData se usa para los nombres de las columnas. Como alternativa más abstracta, consulte Apache Commons DbUtils , que utiliza Class Literals como Runtime-Type Tokens y ResultSetMetaData para crear de forma segura instancias de datos de filas.

  • JDBCModel delega la recuperación de fila a un JDBCWorker privado; invoca publish() en cada fila recuperada del ResultSet ; porque process() ejecuta en el EDT, el trabajador puede optimizar el número de eventos de modelo de tabla que se fireTableRowsInserted() en nombre del modelo principal utilizando fireTableRowsInserted() .

  • Del mismo modo, su implementación de delete() debería residir en JDBCModel , no en la GUI; debe fireTableRowsDeleted() después de que la fila se elimine de la base de datos y se elimine de los data .

  • Agregue Thread.sleep() al bucle de fondo del trabajador para ver el efecto de aumentar artificialmente la latencia.

  • Use setProgress() y PropertyChangeListener , que se muestran aquí , para mostrar el progreso; un JOptionPane cuando está done() puede ser superfluo.

  • getPreferredScrollableViewportSize() para personalizar el tamaño del JScrollPane de la tabla.

  • Evite nombres de clase, por ejemplo, TableModel , que colisionen con nombres de API comunes.

  • Aquí se examina una variación que implementa el filtrado en vivo en la vista.

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

Estoy haciendo un Proyecto de GUI para la base de datos. Hay dos clases que son para GUI''s . Y la clase de conector se usa para conectarse desde las credenciales del usuario. Si las credenciales son correctas, obtenga todos los datos en el from AbstractTableModel . Cuando se ejecuta el programa, la primera GUI tiene un botón en el que hacemos clic y recupera todos los datos en TableModel subyacente. Pero estoy enfrentando dos problemas. Primero en la clase GUI2 , a veces se abre así.


y a veces se muestra así

http://imageshack.com/i/p3gBDt9Ej

No sé por qué está sucediendo. Y el segundo problema es cuando seleccionamos cualquier fila de la tabla y DeleteSelectedRow clic en el botón DeleteSelectedRow para eliminar la fila. Este botón tiene un ActionListener en la clase GUI2 . Pero lo que quiero es actualizar automáticamente la tabla cuando se ha eliminado la fila. ¿Cómo puedo hacer eso?

clase para la primera 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); } }

Clase de conector

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

clase para la segunda 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); } }

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