计算JTable中的运行总计

我需要填充JTable中的一列来计算运行总计,如下所示。

ID Name Position Salary Total === ====== ========== ======= ====== 1. Peter Programmer 40,000 40,000 2. Paul Manager 25,000 65,000 3. Mary Designer 25,000 90,000 

我有4个类 – 每个员工一个实体类,一个表模型类,一个扩展JFrame以显示输出的主类,以及一个用于格式化最后两列中的数字的类。 代码如下所示。 我遇到的问题是运行总计没有正确计算。 由于代码目前正在编写,第一个总数是80,000太高,这让我觉得它是第三个员工,然后再转到第二个员工。 正确添加每个后续总数,但当然最终总数减少了80,000。 这是输出现在的样子:

 ID Name Position Salary Total === ====== ========== ======= ====== 1. Peter Programmer 40,000 120,000 2. Paul Manager 25,000 145,000 3. Mary Designer 25,000 170,000 

请注意,在下面的代码中,表可以按列重新排序,并且包含一个侦听器以重新计算运行总计。 这个函数需要在重新排序之前归零,现在还没有这样做。 如果有人能告诉我为什么会这样,以及如何解决它,我将非常感激。

 public class JTableRunningTotalExample extends JFrame { private static final long serialVersionUID = 1L; private JTable table; private TableModel tableModel; private NumberCellFormatter numberCellFormatter = new NumberCellFormatter(); private int salarySum = 0; private List listEmployees; private Employee employee; public JTableRunningTotalExample() { super("JTable Sorting Example"); createListEmployees(); tableModel = new EmployeeTableModel(listEmployees); table = new JTable(tableModel); for (int j=3; j<5; j++) { table.getColumnModel().getColumn(j).setCellRenderer(numberCellFormatter); } TableRowSorter sorter = new TableRowSorter(table.getModel()); table.setRowSorter(sorter); List sortKeys = new ArrayList(); int columnIndexToSort = 0; sortKeys.add(new RowSorter.SortKey(columnIndexToSort, SortOrder.ASCENDING)); sorter.setSortKeys(sortKeys); sorter.sort(); sorter.addRowSorterListener(new RowSorterListener() { public void sorterChanged(RowSorterEvent evt) { int columnIndex = 0; salarySum = 0; for (int i = 0; i < table.getRowCount(); i++) { table.setValueAt(i + 1, i, columnIndex); } } }); add(new JScrollPane(table), BorderLayout.CENTER); pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void createListEmployees() { listEmployees = new ArrayList(); listEmployees.add(new Employee("Peter", "Manager", 40000)); listEmployees.add(new Employee("Paul", "Programmer", 25000)); listEmployees.add(new Employee("Mary", "Designer", 25000)); listEmployees.add(new Employee("Donald", "Leader", 30000)); listEmployees.add(new Employee("Tom", "Designer", 28000)); listEmployees.add(new Employee("Samantha", "Analyst", 50000)); listEmployees.add(new Employee("Jerome", "Programmer", 32000)); listEmployees.add(new Employee("Jonathon", "Developer", 29000)); listEmployees.add(new Employee("Kevin", "Programmer", 23000)); listEmployees.add(new Employee("Anthony", "Programmer", 23000)); listEmployees.add(new Employee("John", "Designer", 33000)); listEmployees.add(new Employee("David", "Developer", 28000)); listEmployees.add(new Employee("Harry", "Designer", 31000)); listEmployees.add(new Employee("Charles", "Programmer", 26000)); listEmployees.add(new Employee("Joseph", "Manager", 40000)); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JTableRunningTotalExample frame = new JTableRunningTotalExample(); frame.setVisible(true); frame.setLocationRelativeTo(null); } }); } } 

*****表模型类*****

 public class EmployeeTableModel extends AbstractTableModel { private static final long serialVersionUID = 1L; private static final int COLUMN_NUM = 0; private static final int COLUMN_NAME = 1; private static final int COLUMN_JOB = 2; private static final int COLUMN_SALARY = 3; private static final int COLUMN_SUM = 4; private String[] columnNames = { "No #", "Name", "Job", "Salary", "Total Payroll" }; private List listEmployees; private int salarySum = 0; private Employee employee; public EmployeeTableModel(List listEmployees) { this.listEmployees = listEmployees; int indexCount = 1; for (Employee employee : listEmployees) { employee.setIndex(indexCount++); } } @Override public int getColumnCount() { return columnNames.length; } @Override public int getRowCount() { return listEmployees.size(); } @Override public String getColumnName(int columnIndex) { return columnNames[columnIndex]; } @Override public Class getColumnClass(int columnIndex) { if (listEmployees.isEmpty()) { return Object.class; } return getValueAt(0, columnIndex).getClass(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { employee = listEmployees.get(rowIndex); Object returnValue = null; switch (columnIndex) { case COLUMN_NUM: returnValue = employee.getIndex(); break; case COLUMN_NAME: returnValue = employee.getName(); break; case COLUMN_JOB: returnValue = employee.getJob(); break; case COLUMN_SALARY: returnValue = employee.getSalary(); break; case COLUMN_SUM: salarySum = salarySum + employee.getSalary(); returnValue = salarySum ; break; default: throw new IllegalArgumentException("Invalid column index"); } return returnValue; } } 

***** Empoloyee实体类*****

 public class Employee { private int index; private String name; private String job; private int salary; public Employee(String name, String job, int salary) { this.name = name; this.job = job; this.salary = salary; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public int getSalary() { return salary; } public void setSalary(int age) { this.salary = age; } } 

***** Cell Renderer class *****

 public class NumberCellFormatter extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; private NumberFormat numberFormat = new DecimalFormat("#,###,###"); private double formattedNumber; public double setNumberFormat(String number) { formattedNumber = Double.parseDouble(numberFormat.format(number)); return formattedNumber; } @Override public Component getTableCellRendererComponent(JTable jTable, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c = super.getTableCellRendererComponent(jTable, value, isSelected, hasFocus, row, column); if (c instanceof JLabel && value instanceof Number) { JLabel label = (JLabel) c; label.setHorizontalAlignment(JLabel.RIGHT); Number num = (Number) value; String text = numberFormat.format(num); label.setText(text); label.setForeground(num.doubleValue() < 0 ? Color.RED : Color.BLACK); } return c; } } 

如“ 如何使用表:排序和过滤 ”中所述,“使用分拣机时,请始终记住转换单元格坐标。” 因为JTable排序发生在视图中,所以在计算getValueAt()实现中COLUMN_SUM的部分和时使用视图坐标,并禁用该列的排序,如下所示。

 @Override public Object getValueAt(int rowIndex, int columnIndex) { Employee employee = listEmployees.get(rowIndex); switch (columnIndex) { … case COLUMN_SUM: return partialSum(rowIndex); … } } private int partialSum(int row) { int viewRow = table.convertRowIndexToView(row); int viewCol = table.convertColumnIndexToView(COLUMN_SALARY); int sum = (int) table.getValueAt(viewRow, viewCol); for (int i = 0; i < viewRow; i++) { sum += (int) table.getValueAt(i, viewCol); } return sum; } 

图片

经测试:

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import javax.swing.DefaultRowSorter; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableModel; /** @see https://stackoverflow.com/a/37892395/230513 */ public class JTableRunningTotalExample extends JFrame { private final NumberCellFormatter numberCellFormatter = new NumberCellFormatter(); public JTableRunningTotalExample() { super("JTable Sorting Example"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JTable table = new JTable() { @Override public Dimension getPreferredScrollableViewportSize() { return new Dimension(500, getRowCount() * getRowHeight()); } }; List listEmployees = createListEmployees(); TableModel model = new EmployeeTableModel(table, listEmployees); table.setModel(model); table.setAutoCreateRowSorter(true); DefaultRowSorter sorter = (DefaultRowSorter) table.getRowSorter(); sorter.setSortable(4, false); for (int j = 3; j < 5; j++) { table.getColumnModel().getColumn(j).setCellRenderer(numberCellFormatter); } add(new JScrollPane(table), BorderLayout.CENTER); pack(); } private List createListEmployees() { List listEmployees = new ArrayList<>(); listEmployees.add(new Employee("Peter", "Manager", 40000)); listEmployees.add(new Employee("Paul", "Programmer", 25000)); listEmployees.add(new Employee("Mary", "Designer", 25000)); listEmployees.add(new Employee("Donald", "Leader", 30000)); listEmployees.add(new Employee("Tom", "Designer", 28000)); listEmployees.add(new Employee("Samantha", "Analyst", 50000)); listEmployees.add(new Employee("Jerome", "Programmer", 32000)); listEmployees.add(new Employee("Jonathon", "Developer", 29000)); listEmployees.add(new Employee("Kevin", "Programmer", 23000)); listEmployees.add(new Employee("Anthony", "Programmer", 23000)); listEmployees.add(new Employee("John", "Designer", 33000)); listEmployees.add(new Employee("David", "Developer", 28000)); listEmployees.add(new Employee("Harry", "Designer", 31000)); listEmployees.add(new Employee("Charles", "Programmer", 26000)); listEmployees.add(new Employee("Joseph", "Manager", 40000)); return listEmployees; } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JTableRunningTotalExample frame = new JTableRunningTotalExample(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } private static class EmployeeTableModel extends AbstractTableModel { private static final int COLUMN_NUM = 0; private static final int COLUMN_NAME = 1; private static final int COLUMN_JOB = 2; private static final int COLUMN_SALARY = 3; private static final int COLUMN_SUM = 4; private String[] columnNames = {"No", "Name", "Job", "Salary", "Total Payroll"}; JTable table; private List listEmployees; public EmployeeTableModel(JTable table, List listEmployees) { this.table = table; this.listEmployees = listEmployees; int indexCount = 1; for (Employee employee : listEmployees) { employee.setIndex(indexCount++); } } @Override public int getColumnCount() { return columnNames.length; } @Override public int getRowCount() { return listEmployees.size(); } @Override public String getColumnName(int columnIndex) { return columnNames[columnIndex]; } @Override public Class getColumnClass(int columnIndex) { return getValueAt(0, columnIndex).getClass(); } @Override public Object getValueAt(int rowIndex, int columnIndex) { Employee employee = listEmployees.get(rowIndex); switch (columnIndex) { case COLUMN_NUM: return employee.getIndex(); case COLUMN_NAME: return employee.getName(); case COLUMN_JOB: return employee.getJob(); case COLUMN_SALARY: return employee.getSalary(); case COLUMN_SUM: return partialSum(rowIndex); default: throw new IllegalArgumentException("Invalid column index"); } } private int partialSum(int row) { int viewRow = table.convertRowIndexToView(row); int viewCol = table.convertColumnIndexToView(COLUMN_SALARY); int sum = (int) table.getValueAt(viewRow, viewCol); for (int i = 0; i < viewRow; i++) { sum += (int) table.getValueAt(i, viewCol); } return sum; } } private static class Employee { private int index; private String name; private String job; private int salary; public Employee(String name, String job, int salary) { this.name = name; this.job = job; this.salary = salary; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public int getSalary() { return salary; } public void setSalary(int age) { this.salary = age; } } private static class NumberCellFormatter extends DefaultTableCellRenderer { private static final long serialVersionUID = 1L; private NumberFormat numberFormat = NumberFormat.getCurrencyInstance(); private double formattedNumber; public double setNumberFormat(String number) { formattedNumber = Double.parseDouble(numberFormat.format(number)); return formattedNumber; } @Override public Component getTableCellRendererComponent(JTable jTable, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c = super.getTableCellRendererComponent(jTable, value, isSelected, hasFocus, row, column); if (c instanceof JLabel && value instanceof Number) { JLabel label = (JLabel) c; label.setHorizontalAlignment(JLabel.RIGHT); Number num = (Number) value; String text = numberFormat.format(num); label.setText(text); label.setForeground(num.doubleValue() < 0 ? Color.RED : Color.BLACK); } return c; } } } 

也许你可以在rowIndex上检查零之后改变。

 salarySum = (Integer)getValueAt(rowIndex-1, columnIndex)+ employee.getSalary(); 

并且在rowIndex = 0的情况下; 它应该如下。

 salarySum = employee.getSalary(); 

每次调用getValueAt必须为所请求的单元格生成值,而不依赖于之前调用getValueAt的结果,因为您无法控制调用getValueAt时间和频率。

每次请求时重新计算正确的总数,如@ trashgod的示例所示。