我一直在寻找一整天,我仍然找不到简单的问题:当我在另一个编辑时,如何让JTable单元更新它的值?
我想以某种方式使用fireTableCellUpdated
,但我真的不明白如何使用它,何时以及在什么对象上使用它。
我想要的是获得某种倾听者是否会听取这些值的变化。在这个特殊情况下,我有可编辑的第三列,其中我存储了金额,我希望该监听器自动计算并设置一行中其他单元格中的值。我想出了类似的东西:
@Override
public void tableChanged(TableModelEvent e)
{
BigDecimal withoutTax, tax, withTax;
for(int i = 0; i < table.getRowCount(); i++)
{
BigDecimal amount = new BigDecimal(String.valueOf(table.getValueAt(i, 3)).replace(",", "."));
BigDecimal price = new BigDecimal(String.valueOf(table.getValueAt(i, 4)).replace(",", "."));
withoutTax = amount.multiply(price, new MathContext(2));
table.setValueAt(withoutTax, i, 5);
tax = withoutTax.multiply(new BigDecimal(0.23), new MathContext(2));
table.setValueAt(tax, i, 7);
withTax = withoutTax.add(tax, new MathContext(2));
table.setValueAt(withTax, i, 8);
}
}
但是这会产生StackOverflowError
,我猜这是因为table.setValueAt
会触发tableChanged
侦听器,所以它会进入无限循环。
有人可以解释我如何实现这一目标?
答案 0 :(得分:3)
tableChanged
发生变化时,{p> TableModel
被调用,该变更由setValueAt
方法触发,并且在您周围...
解决方案?在setValue
...
TableModel
方法中进行
public class TestModel extends ... { // Some TableModel
//...
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 3) {
// Set the value been passed to in (probably from the editor)...
fireTableCellUpdated(rowIndex, columnIndex);
BigDecimal amount = new BigDecimal(String.valueOf(getValueAt(rowIndex, 3)).replace(",", "."));
BigDecimal price = new BigDecimal(String.valueOf(getValueAt(rowIndex, 4)).replace(",", "."));
BigDecimal withoutTax = amount.multiply(price, new MathContext(2));
// Set the value for row x 5 directly within the backing store of the model...
//table.setValueAt(withoutTax, i, 5);
BigDecimal tax = withoutTax.multiply(new BigDecimal(0.23), new MathContext(2));
// Set the value for row x 7 directly within the backing store of the model...
//table.setValueAt(tax, i, 7);
BigDecimal withTax = withoutTax.add(tax, new MathContext(2));
// Set the value for row x 8 directly within the backing store of the model...
//table.setValueAt(withTax, i, 8);
fireTableCellUpdated(rowIndex, 5);
fireTableCellUpdated(rowIndex, 7);
fireTableCellUpdated(rowIndex, 8);
// It might actually be easier to use...
//fireTableRowsUpdated(rowIndex, rowIndex);
}
}
例如......
这是一个基本的例子,虽然它只使用一行,但这个想法适用于所有相同的多行......
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTable table = new JTable(new MultiplicationTableMode());
add(new JScrollPane(table));
}
}
public class MultiplicationTableMode extends AbstractTableModel {
private List<List<Integer>> values;
public MultiplicationTableMode() {
values = new ArrayList<>(1);
List<Integer> cols = new ArrayList<>(11);
for (int index = 0; index < 11; index++) {
cols.add(0);
}
values.add(cols);
}
@Override
public int getRowCount() {
return values.size();
}
@Override
public int getColumnCount() {
return 10;
}
@Override
public String getColumnName(int column) {
return column == 0 ? "?" : "x" + Integer.toString(column);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
List<Integer> columns = values.get(rowIndex);
return columns.get(columnIndex);
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return Integer.class;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) {
if (aValue instanceof Integer) {
List<Integer> columns = values.get(rowIndex);
int intValue = (int) aValue;
columns.set(0, intValue);
for (int index = 1; index < columns.size(); index++) {
columns.set(index, intValue * index);
}
fireTableRowsUpdated(rowIndex, rowIndex);
}
}
}
}
}
我想到,如果其他列值不可编辑,那么您实际上根本不需要维护它们的值,但只要在调用getValueAt
时就可以动态地计算它们,例如..
public class MultiplicationTableMode extends AbstractTableModel {
private List<Integer> values;
public MultiplicationTableMode() {
values = new ArrayList<>(1);
values.add(0);
}
@Override
public int getRowCount() {
return values.size();
}
@Override
public int getColumnCount() {
return 10;
}
@Override
public String getColumnName(int column) {
return column == 0 ? "?" : "x" + Integer.toString(column);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
int value = values.get(rowIndex);
if (columnIndex > 0) {
value *= columnIndex;
}
return value;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return Integer.class;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 0) {
if (aValue instanceof Integer) {
values.set(rowIndex, (int)aValue);
fireTableRowsUpdated(rowIndex, rowIndex);
}
}
}
}