I need to populate a column in my JTable that computes a running total as is shown below.
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
I have 4 classes--one entity class for each employee, one table model class, one main class that extends JFrame to show the output, and one to format the numbers in the last two columns. Code is shown below. The problem I'm having is that the running total is not computed correctly. As the code is currently written, the first total is 80,000 too high, which makes me think it is adding the first employee three times before moving to the second. Each subsequent total is correctly added, but of course the final total is off by 80,000.
Here is what the output looks like now:
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
Notice in the code below that the table can be re-sorted by column and a listener is included to re-calculate the running totals. This function needs to be zeroed out prior to re-sorting and it's not doing that now. If anyone can tell me why this is happening and how to fix it, I would be very grateful.
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<Employee> 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<TableModel> sorter = new TableRowSorter<>(table.getModel());
table.setRowSorter(sorter);
List<RowSorter.SortKey> 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);
}
});
}
}
*****Table Model class*****
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<Employee> listEmployees;
private int salarySum = 0;
private Employee employee;
public EmployeeTableModel(List<Employee> 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 entity class*****
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;
}
}
See Question&Answers more detail:
os