Java JTable setValueAt StackOverflower错误

Java JTable setValueAt StackOverflower错误,java,swing,jtable,stack-overflow,Java,Swing,Jtable,Stack Overflow,我搜索了一整天,仍然找不到解决问题的简单方法:当我在另一个单元格中编辑JTable cell时,如何让它更新其值? 我想以某种方式使用fireTableCellUpdated,但我真的不明白如何使用它,何时在什么对象上使用它 我想得到的是某种类型的监听器,无论值是否改变,它都会监听。在这个特定的场景中,我有一个可编辑的第三列,我在其中存储了金额,我希望侦听器自动计算并设置行中其他单元格中的值。我想出了这样的办法: @Override public void tableChanged(TableM

我搜索了一整天,仍然找不到解决问题的简单方法:当我在另一个单元格中编辑JTable cell时,如何让它更新其值?

我想以某种方式使用
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);
    }
}
@覆盖
公共作废表已更改(TableModelEvent e)
{
大十进制无税,税,有税;
对于(int i=0;i
但这会导致
StackOverflowerError
,我猜这是因为
table.setValueAt
触发
tableChanged
侦听器,所以它将进入无限循环


有人能告诉我如何实现吗?
tableChanged
在发生对
TableModel
的更改时被调用,该更改由
setValueAt
方法触发,然后在您周围

解决方案是什么?在
TableModel
setValue
方法中执行此操作

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

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

}
这是一个基本的例子,虽然它只使用一行,但这一想法同样适用于多行


tableChanged
在对
TableModel
进行更改时被调用,该更改由
setValueAt
方法触发,并在您周围

解决方案是什么?在
TableModel
setValue
方法中执行此操作

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

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

}
这是一个基本的例子,虽然它只使用一行,但这一想法同样适用于多行


tableChanged
在对
TableModel
进行更改时被调用,该更改由
setValueAt
方法触发,然后在您周围执行…解决方案?在
setValue
方法中执行该操作,并触发范围updateHmm,您的意思是像在表模型中重写setValue()一样?你说的“范围更新”是什么意思。我的意思是“范围更新”是使用
fireTableRowsUpdated
一步更新整行可能更有效,而不是在对
TableModel
进行更改时尝试在4个单独的事件调用中更新4个单元格,由
setValueAt
方法触发,然后在您周围…解决方案?在
setValue
方法中执行该操作,并触发范围updateHmm,您的意思是像在表模型中重写setValue()一样?你说的“范围更新”是什么意思。我的意思是“范围更新”是使用
fireTableRowsUpdated
一步更新整行可能更有效,而不是尝试在4个单独的事件调用中更新4个单元格,这就解释了很多问题,我将在几分钟内尝试它这是“一般”想法;)嘿,等一下。当我触发该方法时,仍然不能解决问题?我的意思是,我需要某种
while(true)
循环来检查值是否发生了变化,如果发生了变化,则会触发
setValueAt
,我不确定我是否理解。当单元格编辑器“停止”时,
JTable
将调用
TableModel
setValueAt
方法,这将允许您确定已更新的值(单元格的新值),然后进行二次计算,为什么需要调用
setValueAt
?是和否。
DefaultTableModel
可以,但是
AbstractTableModel
不可以,这就是(正如您在两个示例中看到的)我亲自调用
fireXxx
方法的原因。现在,这解释了很多问题,我将在几分钟内尝试一下这是“一般”想法;)嘿,等一下。当我触发该方法时,仍然不能解决问题?我的意思是,我需要某种
while(true)
循环来检查值是否发生了变化,如果发生了变化,则会触发
setValueAt
,我不确定我是否理解。当单元格编辑器“停止”时,
JTable
将调用
TableModel
setValueAt
方法,这将允许您确定已更新的值(单元格的新值),然后进行二次计算,为什么需要调用
setValueAt
?是和否。
DefaultTableModel
有,但
AbstractTableModel
没有,这就是我自己实际调用
fireXxx
方法的原因(如两个示例所示)