将监听器设置为TableModel以根据需要进行更新

我正在尝试根据是添加还是删除项目来更新GUI中的JTable。 JTextField中的总价格应根据删除或添加的项目递增或递减。 我知道我应该使用TableModelListener动态更新它。 我还需要在整个JTextField中设置它,但我不确定如何正确处理它。 这是我的代码。

package classes; import java.awt.*; import java.awt.GridLayout; import java.awt.event.*; import java.sql.*; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.swing.*; import javax.swing.Timer; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableModel; import javax.swing.event.*; public class CoffeeTill_GUI extends JFrame { private JPanel contentPane; JLabel orderDescription = new JLabel("Order Description:"); private JTextField totalTF; private double total = 0.0; private double tendered = 0.0; private double change = 0.0; private TableModelListener tableModelListener; // Editing An Order //TableModelListener to listen for changes in the tableModel private void setTableModelListener() { tableModelListener = new TableModelListener() { @Override public void tableChanged(TableModelEvent e) { if (e.getType() == TableModelEvent.UPDATE) { System.out.println("Cell " + e.getFirstRow() + ", " + e.getColumn() + " changed. The new value: " + table.getModel().getValueAt(e.getFirstRow(), e.getColumn())); int row = e.getFirstRow(); int column = e.getColumn(); if (column == 0 || column == 1) { TableModel model = table.getModel(); int quantity = ((Integer) model.getValueAt(row, 0)).intValue(); double price = ((Double) model.getValueAt(row, 1)).doubleValue(); Double value = new Double(quantity * price); model.setValueAt(value, row, 1); } } } }; table.getModel().addTableModelListener(tableModelListener); } // JDBC Driver name and database URL final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; final String DB_URL = "jdbc:mysql://localhost:3306/team_project?useSSL=false"; final String USER_NAME = "root"; final String PASSWORD = "password"; // sql variables Statement statement = null; ResultSet resultSet = null; // Update JTable when JButton is clicked public void updateTable(int prodIn) { try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD); Statement stmt = conn.createStatement(); String sqlString = "select ProductID, ProductName, Price from product where ProductID = " + prodIn; stmt.executeQuery(sqlString); } catch (Exception e) { e.printStackTrace(); } } // creating new stock item Stock productPrice = new Stock(); Stock productName = new Stock(); JTable table = new JTable(); JButton delButton = new JButton("DEL"); JButton minusButton = new JButton("-"); JButton plusButton = new JButton("+"); /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { CoffeeTill_GUI frame = new CoffeeTill_GUI(); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); frame.setUndecorated(false); frame.setLocationRelativeTo(null); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } // Connection Object Connection connection = null; private JTextField tenderedTF; private JTextField changeTF; /** * Create the frame. */ public CoffeeTill_GUI() { try { connection = (Connection) DriverManager.getConnection(DB_URL, USER_NAME, PASSWORD); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 1200, 686); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); setContentPane(contentPane); contentPane.setLayout(null); // COFFEE PANEL - START ----------------------------------------- JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); tabbedPane.setBounds(20, 74, 796, 563); contentPane.add(tabbedPane); JPanel panel = new JPanel(); tabbedPane.addTab("Coffee", null, panel, null); panel.setLayout(null); JLabel lblCoffee = new JLabel("Americano"); lblCoffee.setHorizontalAlignment(SwingConstants.CENTER); lblCoffee.setFont(new Font("Tahoma", Font.PLAIN, 30)); lblCoffee.setBounds(10, 45, 154, 45); panel.add(lblCoffee); JLabel label = new JLabel("Cappucino"); label.setHorizontalAlignment(SwingConstants.CENTER); label.setFont(new Font("Tahoma", Font.PLAIN, 30)); label.setBounds(10, 117, 154, 45); panel.add(label); JLabel label_1 = new JLabel("Espresso"); label_1.setHorizontalAlignment(SwingConstants.CENTER); label_1.setFont(new Font("Tahoma", Font.PLAIN, 30)); label_1.setBounds(10, 191, 154, 45); panel.add(label_1); JLabel label_2 = new JLabel("Latte"); label_2.setHorizontalAlignment(SwingConstants.CENTER); label_2.setFont(new Font("Tahoma", Font.PLAIN, 30)); label_2.setBounds(10, 274, 154, 45); panel.add(label_2); JLabel label_3 = new JLabel("Mocha"); label_3.setHorizontalAlignment(SwingConstants.CENTER); label_3.setFont(new Font("Tahoma", Font.PLAIN, 30)); label_3.setBounds(10, 355, 154, 45); panel.add(label_3); JLabel label_4 = new JLabel("Macchiato"); label_4.setHorizontalAlignment(SwingConstants.CENTER); label_4.setFont(new Font("Tahoma", Font.PLAIN, 30)); label_4.setBounds(10, 440, 154, 45); panel.add(label_4); JButton americanoSmall = new JButton("SMALL"); americanoSmall.setBounds(191, 45, 164, 45); panel.add(americanoSmall); JButton americanoMedium = new JButton("MEDIUM"); americanoMedium.setBounds(365, 45, 164, 45); panel.add(americanoMedium); JButton americanoLarge = new JButton("LARGE"); americanoLarge.setBounds(539, 45, 164, 45); panel.add(americanoLarge); JButton cappuchinoSmall = new JButton("SMALL"); cappuchinoSmall.setBounds(191, 117, 164, 45); panel.add(cappuchinoSmall); JButton cappuchinoMedium = new JButton("MEDIUM"); cappuchinoMedium.setBounds(365, 117, 164, 45); panel.add(cappuchinoMedium); JButton cappuchinoLarge = new JButton("LARGE"); cappuchinoLarge.setBounds(539, 117, 164, 45); panel.add(cappuchinoLarge); JButton espressoSmall = new JButton("SMALL"); espressoSmall.setBounds(191, 191, 164, 45); panel.add(espressoSmall); JButton espressoMedium = new JButton("MEDIUM"); espressoMedium.setBounds(365, 191, 164, 45); panel.add(espressoMedium); JButton espressoLarge = new JButton("LARGE"); espressoLarge.setBounds(539, 191, 164, 45); panel.add(espressoLarge); JButton latteSmall = new JButton("SMALL"); latteSmall.setBounds(191, 274, 164, 45); panel.add(latteSmall); JButton latteMedium = new JButton("MEDIUM"); latteMedium.setBounds(365, 274, 164, 45); panel.add(latteMedium); JButton latteLarge = new JButton("LARGE"); latteLarge.setBounds(539, 274, 164, 45); panel.add(latteLarge); JButton mochaSmall = new JButton("SMALL"); mochaSmall.setBounds(191, 355, 164, 45); panel.add(mochaSmall); JButton mochaMedium = new JButton("MEDIUM"); mochaMedium.setBounds(365, 355, 164, 45); panel.add(mochaMedium); JButton mochaLarge = new JButton("LARGE"); mochaLarge.setBounds(539, 355, 164, 45); panel.add(mochaLarge); JButton macchiatoSmall = new JButton("SMALL"); macchiatoSmall.setBounds(191, 440, 164, 45); panel.add(macchiatoSmall); JButton macchiatoMedium = new JButton("MEDIUM"); macchiatoMedium.setBounds(365, 440, 164, 45); panel.add(macchiatoMedium); JButton macchiatoLarge = new JButton("LARGE"); macchiatoLarge.setBounds(539, 440, 164, 45); panel.add(macchiatoLarge); // COFFEE PANEL - END ----------------------------------------- // COLD DRINKS PANELS - START ----------------------------------------- JPanel panel_1 = new JPanel(); tabbedPane.addTab("Cold Drinks", null, panel_1, null); panel_1.setLayout(new GridLayout(2, 2)); ImageIcon waterIcon, cokeIcon, spriteIcon, fantaIcon; JButton waterButton, cokeButton, spriteButton, fantaButton; panel_1.add(waterButton = new JButton(waterIcon = new ImageIcon("image/water.jpg"))); panel_1.add(cokeButton = new JButton(cokeIcon = new ImageIcon("image/coke.jpg"))); panel_1.add(spriteButton = new JButton(spriteIcon = new ImageIcon("image/sprite.jpg"))); panel_1.add(fantaButton = new JButton(fantaIcon = new ImageIcon("image/fanta.jpg"))); // COLD DRINKS PANEL - END ----------------------------------------- // SANDWICHES - START ----------------------------------------- JButton hamAndCheese, bltButton, tunaAndSweetcorn, chickenAndHam, hamAndCheesePanini; JPanel panel_2 = new JPanel(); tabbedPane.addTab("Sandwiches", null, panel_2, null); panel_2.setLayout(new GridLayout(5, 1)); panel_2.add(hamAndCheese = new JButton("Ham & Cheese")); panel_2.add(bltButton = new JButton("BLT")); panel_2.add(tunaAndSweetcorn = new JButton("Tuna & Sweetcorn")); panel_2.add(chickenAndHam = new JButton("Chicken & Ham")); panel_2.add(hamAndCheesePanini = new JButton("Ham & Cheese Panini")); // SANDWICHES - END ----------------------------------------- // PASTRIES - START ----------------------------------------- JButton danishPastryJbt, muffinJbt, cinnamonRoleJbt, profiteroleJbt, eclairJbt, croissantJbt; JPanel panel_3 = new JPanel(); panel_3.setLayout(new GridLayout(6, 1)); tabbedPane.addTab("Pastries", null, panel_3, null); panel_3.add(danishPastryJbt = new JButton("Danish Pastry")); panel_3.add(muffinJbt = new JButton("Muffin")); panel_3.add(cinnamonRoleJbt = new JButton("Cinnamon Role")); panel_3.add(profiteroleJbt = new JButton("Profiterole")); panel_3.add(eclairJbt = new JButton("Eclair")); panel_3.add(croissantJbt = new JButton("Croissant")); orderDescription.setFont(new Font("Tahoma", Font.PLAIN, 20)); orderDescription.setBounds(845, 55, 214, 33); contentPane.add(orderDescription); // ORDER - END ----------------------------------------- // HEADING - START ----------------------------------------- JLabel lblUserEmployee = new JLabel("User: Employee1"); lblUserEmployee.setFont(new Font("Tahoma", Font.PLAIN, 20)); lblUserEmployee.setBounds(20, 11, 204, 33); contentPane.add(lblUserEmployee); JLabel lblJavaHouseCoffee = new JLabel("Java House Coffee"); lblJavaHouseCoffee.setHorizontalAlignment(SwingConstants.CENTER); lblJavaHouseCoffee.setFont(new Font("Tahoma", Font.PLAIN, 40)); lblJavaHouseCoffee.setBounds(333, 11, 480, 60); contentPane.add(lblJavaHouseCoffee); // Setting the Time on the GUI JLabel lblTime = new JLabel(""); String timeStamp = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss").format(Calendar.getInstance().getTime()); lblTime.setFont(new Font("Tahoma", Font.PLAIN, 18)); lblTime.setBounds(650, 0, 120, 30); lblTime.setText(timeStamp + ""); lblTime.setVisible(true); int delay = 1000; // milliseconds ActionListener taskPerformer = new ActionListener() { public void actionPerformed(ActionEvent evt) { String date = new java.text.SimpleDateFormat("HH:mm:ss") .format(new java.util.Date(System.currentTimeMillis())); lblTime.setText("" + Calendar.getInstance().getTime()); } }; new Timer(delay, taskPerformer).start(); lblTime.setHorizontalAlignment(SwingConstants.CENTER); lblTime.setFont(new Font("Tahoma", Font.PLAIN, 20)); lblTime.setBounds(914, 11, 244, 45); contentPane.add(lblTime); // add header of the table String columns[] = new String[] { "Product Name", "Price" }; DefaultTableModel dtm = new DefaultTableModel(columns, 0); dtm.setColumnIdentifiers(columns); table.setModel(dtm); // round the prices values pulled from DB to 2 Decimal Places table.getColumnModel().getColumn(1).setCellRenderer(new DecimalFormatRenderer()); getContentPane().add(new JScrollPane(table)); table.setFont(new Font("Serif", Font.PLAIN, 18)); // add header of the table JScrollPane scrollPaneTable = new JScrollPane(table); scrollPaneTable.setBounds(845, 94, 329, 241); contentPane.add(scrollPaneTable); JPanel panel_5 = new JPanel(); scrollPaneTable.setColumnHeaderView(panel_5); panel_5.setLayout(new BorderLayout()); JLabel totalJLabel = new JLabel("Total €"); totalJLabel.setFont(new Font("Tahoma", Font.PLAIN, 20)); totalJLabel.setBounds(899, 400, 63, 45); contentPane.add(totalJLabel); totalTF = new JTextField(); totalTF.setFont(new Font("Tahoma", Font.PLAIN, 20)); totalTF.setBounds(970, 400, 204, 45); contentPane.add(totalTF); totalTF.setColumns(10); totalTF.setEditable(false); delButton.setBounds(845, 346, 96, 45); contentPane.add(delButton); delButton.setFont(new Font("Tahoma", Font.PLAIN, 15)); minusButton.setBounds(963, 346, 96, 45); contentPane.add(minusButton); minusButton.setFont(new Font("Tahoma", Font.PLAIN, 15)); plusButton.setBounds(1083, 346, 87, 45); contentPane.add(plusButton); plusButton.setFont(new Font("Tahoma", Font.PLAIN, 15)); JLabel tenderedJLabel = new JLabel("Tendered €"); tenderedJLabel.setFont(new Font("Tahoma", Font.PLAIN, 20)); tenderedJLabel.setBounds(858, 456, 102, 45); contentPane.add(tenderedJLabel); tenderedTF = new JTextField(); tenderedTF.setFont(new Font("Tahoma", Font.PLAIN, 20)); tenderedTF.setBounds(972, 456, 202, 45); contentPane.add(tenderedTF); tenderedTF.setColumns(10); JLabel changeJlabel = new JLabel("Change €"); changeJlabel.setFont(new Font("Tahoma", Font.PLAIN, 20)); changeJlabel.setBounds(878, 521, 84, 37); contentPane.add(changeJlabel); changeTF = new JTextField(); changeTF.setFont(new Font("Tahoma", Font.PLAIN, 20)); changeTF.setEditable(false); changeTF.setBounds(972, 512, 202, 46); contentPane.add(changeTF); changeTF.setColumns(10); // Delete row from JTable when clicked by user delButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int viewIndex = table.getSelectedRow(); if (viewIndex != -1) { // converts the row index in the view to the appropriate // index in the model int modelIndex = table.convertRowIndexToModel(viewIndex); DefaultTableModel model = (DefaultTableModel) table.getModel(); model.removeRow(modelIndex); } } }); table.getTableHeader().setReorderingAllowed(false); // HEADING - END ----------------------------------------- // Small Americano ActionListener americanoSmall.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { String query = "select ProductName, Price from product where ProductID = 24"; java.sql.PreparedStatement pst = connection.prepareStatement(query); ResultSet rs = pst.executeQuery(); // Loop through the ResultSet and transfer in the Model java.sql.ResultSetMetaData rsmd = rs.getMetaData(); int colNo = rsmd.getColumnCount(); while (rs.next()) { Object[] objects = new Object[colNo]; for (int i = 0; i < colNo; i++) { objects[i] = rs.getObject(i + 1); } DefaultTableModel model = (DefaultTableModel) table.getModel(); model.addRow(objects); Stock s = new Stock(); // deduct stock from db from // s1.deductStock(24); total = total + s.getItemPrice(24); totalTF.setText(String.valueOf(total)); totalTF.setText(String.format("%.2f", total)); } TableModel model = (DefaultTableModel) table.getModel(); table.setModel(model); } catch (Exception e1) { e1.printStackTrace(); } } }); americanoMedium.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { String query = "select ProductName, Price from product where ProductID = 25"; java.sql.PreparedStatement pst = connection.prepareStatement(query); ResultSet rs = pst.executeQuery(); // Loop through the ResultSet and transfer in the Model java.sql.ResultSetMetaData rsmd = rs.getMetaData(); int colNo = rsmd.getColumnCount(); while (rs.next()) { Object[] objects = new Object[colNo]; for (int i = 0; i < colNo; i++) { objects[i] = rs.getObject(i + 1); } DefaultTableModel model = (DefaultTableModel) table.getModel(); model.addRow(objects); Stock s = new Stock(); // deduct stock from db from // s1.deductStock(24); total = total + s.getItemPrice(25); totalTF.setText(String.valueOf(total)); totalTF.setText(String.format("%.2f", total)); } TableModel model = (DefaultTableModel) table.getModel(); table.setModel(model); } catch (Exception e2) { e2.printStackTrace(); } } }); americanoLarge.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { String query = "select ProductName, Price from product where ProductID = 26"; java.sql.PreparedStatement pst = connection.prepareStatement(query); ResultSet rs = pst.executeQuery(); // Loop through the ResultSet and transfer in the Model java.sql.ResultSetMetaData rsmd = rs.getMetaData(); int colNo = rsmd.getColumnCount(); while (rs.next()) { Object[] objects = new Object[colNo]; for (int i = 0; i < colNo; i++) { objects[i] = rs.getObject(i + 1); } DefaultTableModel model = (DefaultTableModel) table.getModel(); model.addRow(objects); Stock s = new Stock(); // deduct stock from db from // s1.deductStock(24); total = total + s.getItemPrice(26); totalTF.setText(String.valueOf(total)); totalTF.setText(String.format("%.2f", total)); } TableModel model = (DefaultTableModel) table.getModel(); table.setModel(model); } catch (Exception e2) { e2.printStackTrace(); } } }); cappuchinoSmall.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { String query = "select ProductName, Price from product where ProductID = 30"; java.sql.PreparedStatement pst = connection.prepareStatement(query); ResultSet rs = pst.executeQuery(); // Loop through the ResultSet and transfer in the Model java.sql.ResultSetMetaData rsmd = rs.getMetaData(); int colNo = rsmd.getColumnCount(); while (rs.next()) { Object[] objects = new Object[colNo]; for (int i = 0; i < colNo; i++) { objects[i] = rs.getObject(i + 1); } DefaultTableModel model = (DefaultTableModel) table.getModel(); model.addRow(objects); Stock s = new Stock(); // deduct stock from db from // s1.deductStock(24); total = total + s.getItemPrice(30); totalTF.setText(String.valueOf(total)); totalTF.setText(String.format("%.2f", total)); } TableModel model = (DefaultTableModel) table.getModel(); table.setModel(model); } catch (Exception e2) { e2.printStackTrace(); } } }); cappuchinoMedium.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { String query = "select ProductName, Price from product where ProductID = 31"; java.sql.PreparedStatement pst = connection.prepareStatement(query); ResultSet rs = pst.executeQuery(); // Loop through the ResultSet and transfer in the Model java.sql.ResultSetMetaData rsmd = rs.getMetaData(); int colNo = rsmd.getColumnCount(); while (rs.next()) { Object[] objects = new Object[colNo]; for (int i = 0; i < colNo; i++) { objects[i] = rs.getObject(i + 1); } DefaultTableModel model = (DefaultTableModel) table.getModel(); model.addRow(objects); Stock s = new Stock(); // deduct stock from db from // s1.deductStock(24); total = total + s.getItemPrice(31); totalTF.setText(String.valueOf(total)); totalTF.setText(String.format("%.2f", total)); } TableModel model = (DefaultTableModel) table.getModel(); table.setModel(model); } catch (Exception e2) { e2.printStackTrace(); } } }); cappuchinoLarge.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { String query = "select ProductName, Price from product where ProductID = 32"; java.sql.PreparedStatement pst = connection.prepareStatement(query); ResultSet rs = pst.executeQuery(); // Loop through the ResultSet and transfer in the Model java.sql.ResultSetMetaData rsmd = rs.getMetaData(); int colNo = rsmd.getColumnCount(); while (rs.next()) { Object[] objects = new Object[colNo]; for (int i = 0; i < colNo; i++) { objects[i] = rs.getObject(i + 1); } DefaultTableModel model = (DefaultTableModel) table.getModel(); model.addRow(objects); Stock s = new Stock(); // deduct stock from db from // s1.deductStock(24); total = total + s.getItemPrice(32); totalTF.setText(String.valueOf(total)); totalTF.setText(String.format("%.2f", total)); } TableModel model = (DefaultTableModel) table.getModel(); table.setModel(model); } catch (Exception e2) { e2.printStackTrace(); } } }); JButton payButton = new JButton("Pay"); payButton.setBounds(970, 569, 209, 51); contentPane.add(payButton);; }// end class 

所以这是概念的基本certificate。

这样做,它维护了添加/删除/更新的值的内部“代理”/“缓存”。 通过这种方式,它能够使用事件信息简单地更新计数而无需重新迭代模型,这可能非常耗时。

在创建新模型时,应该将侦听器附加到它上面,在填充之前,这将使侦听器有机会获得新行的通知并更新其内部状态。

 import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableModel; public class Test { public static void main(String[] args) { new Test(); } public Test() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame(); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private DefaultTableModel model; private JTextField tallyField; private double tally; public TestPane() { setLayout(new BorderLayout()); tallyField = new JTextField(10); // When loading data, update this value to represent the total // of the data that was loaded tally = 0; model = new DefaultTableModel(new Object[]{"Quanity", "Amount"}, 0); model.addTableModelListener(new TableModelListener() { private Map proxy = new HashMap(); private NumberFormat nf = NumberFormat.getCurrencyInstance(); @Override public void tableChanged(TableModelEvent e) { int firstRow = e.getFirstRow(); int lastRow = e.getLastRow(); double sum = 0; for (int row = Math.min(firstRow, lastRow); row <= Math.max(firstRow, lastRow); row++) { switch (e.getType()) { case TableModelEvent.DELETE: sum -= delete(row); break; case TableModelEvent.INSERT: sum += add(row); break; case TableModelEvent.UPDATE: sum -= delete(row); sum += add(row); break; default: break; } } tally += sum; tallyField.setText(nf.format(tally)); } protected double delete(int row) { double sum = 0; if (proxy.containsKey(row)) { sum = proxy.get(row); } proxy.remove(row); return sum; } protected double add(int row) { int qty = 0; // I hope your model is better setup then mine if (model.getValueAt(row, 0) instanceof String) { qty = Integer.parseInt((String) model.getValueAt(row, 0)); } else if (model.getValueAt(row, 0) instanceof Integer) { qty = (Integer) model.getValueAt(row, 0); } double amount = (Double) model.getValueAt(row, 1); double rowTotal = qty * amount; proxy.put(row, rowTotal); return rowTotal; } }); JTable table = new JTable(model); add(new JScrollPane(table)); JButton add = new JButton("Add"); JButton delete = new JButton("Delete"); add.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { double amount = 1.0; //Math.random() * 1000.0; model.addRow(new Object[]{1, amount}); } }); delete.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int[] rows = table.getSelectedRows(); List selection = new ArrayList<>(rows.length); for (int row : rows) { selection.add(row); } Collections.sort(selection); Collections.reverse(selection); for (int row : selection) { model.removeRow(row); } } }); JPanel footer = new JPanel(new BorderLayout()); JPanel buttons = new JPanel(); buttons.add(add); buttons.add(delete); footer.add(tallyField); footer.add(buttons, BorderLayout.SOUTH); add(footer, BorderLayout.SOUTH); } } } 

为什么我们需要缓存? 因为删除行时,您无法再确定其值。

如果我在一个真正的应用程序中这样做,我会创建一个实现TableModelListener的简单类,但它提供了一个getter来检索tally (因此tally被封装到类中)并使用观察者模式在tally生成时生成通知改变。

这意味着在加载数据时,您可以单独更新模型和“计数监视器”。 当您需要时,更新屏幕上的必填字段。

这可能变得非常复杂,非常快。 我做了类似的事情来生成一个自动计数系统,用于独立于模型计算行和列,因此系统没有耦合到模型结构,除了已知的哪个行/列负责计数