java - JTable 上的自定义单元格返回错误值(并且无法正确显示)

标签 java swing jtable inputverifier

我正在编写一个自定义 POS 系统,并允许用户直接更改 table 上的数量,而不是生成一个对话框。这是表的第一行,其中包含虚拟数据。 (我还没有将它链接到数据库。) enter image description here

Price 和 Amt 都有自定义单元格渲染器(不是任何人都可以知道,因为它们渲染不正确)来显示货币格式。编辑:我取消了自定义编辑器 (不是渲染器,谢谢)并且下面的问题仍然存在

计划是,当用户在数量框中输入数量时,它将更新 amt 单元格(以及屏幕顶部的运行总计)。为此,我创建了一个 validator ,该 validator 将验证数据是否为整数,并将其附加到自定义单元格编辑器,该编辑器仅将 validator 添加到 JTextField。

我的 validator 嵌套在屏幕本身内,因此它可以访问屏幕的字段和表本身。我想将其放入表格模型中,但我发现我无法分辨用户选择了哪个单元格。 (Verify() 有效,所以我省略了)

class QtyVerifier extends InputVerifier
{
    private int qty = 0;
    private BigDecimal pricePerUnit;
    private BigDecimal prevamt;

    @Override
    public boolean shouldYieldFocus(JComponent input) 
    {
        //reset quantity
        this.qty = 0;

        //verify the results
        boolean ok2go = this.verify(input);

        if (ok2go)
        {
            //grab all the current values
            this.qty = new Integer(
                    (String)salesOrderFormTable.getValueAt(rowselected, colselected));
            this.pricePerUnit = new BigDecimal(
                    (String)salesOrderFormTable.getValueAt(rowselected, colselected));
            this.prevamt = new BigDecimal( 
                    (String)salesOrderFormTable.getValueAt(rowselected, colselected));


            //remove previous amount from the total
            addLineCostToRunningTotal(this.prevamt.negate());
            //update sales order total
            addLineCostToRunningTotal(amt);

            //update line total cell
            salesOrderFormTable.setValueAt(actualTotal, rowselected, 6);
            salesOrderFormTable.validate();
        }
        else { ... }
        return ok2go;
    }

    ....
};

这就是事情变得非常奇怪的地方。我告诉 qty,数量仍然是 1。它从单元格中提取所有正确的数据。

Selected: 0,1
Quantity in cell 0,1 is 1
Line price is 1.0
Previous amt is 1.0
New amt is 1.0

好的,很好。所以我将值更改为 5 并按 Enter 键。 enter image description here 它将值更改为 25(解决了此问题),并且还从单元格中提取了错误的数据。

Quantity in cell 0,1 is 5 //this is correct
Line price is 5.0 //this is incorrect. It should be 1.
Previous amt is 5.0 //also incorrect. This also should be 1.
New amt is 25.0 //this WOULD be correct if the previous data was.

我的 table 怎么了?!为什么这会在两个单元格中给我完全错误的信息并将数量单元格更改为我没有输入的内容?有没有更简单的方法来做到这一点(有或没有验证者)?我不能在订单上出现错误的成本。我考虑过将所有值从 double 更改为 BigDecimals 以防止舍入错误,但这甚至不是舍入错误。这完全是错误的。我现在完全迷失了。

最佳答案

鉴于您的代码是高度定制的,并且如果不将所有部分放在一起就很难调试,我会从头开始吸引基本概念,并说使用 TableModel 可以满足这些要求:

  • 验证数字列的输入:如果我们的表模型中的 getColumnClass(...) 返回适当的类,则可以将其委托(delegate)给正确的编辑器。无需自定义编辑器!
  • 更新qty上的amt列或price列更新:这也可以通过表模型来完成,只需覆盖setValueAt(...)正确。
  • 以货币格式显示 priceamt 列:这可以通过提供自定义渲染器(而非编辑器)来完成。

由于没有有关您的表型号的信息,我将使用 DefaultTableModel 说明上述要点,如下所示:

String[] header = new String[] { "qty", "price", "amt" };
DefaultTableModel model = new DefaultTableModel(header, 1) {

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        switch (columnIndex) {
            case 0: return Integer.class;
            case 1: 
            case 2: return Double.class;
        }
        throw new ArrayIndexOutOfBoundsException(columnIndex);
    }

    @Override
    public boolean isCellEditable(int row, int column) {
        return column < 2;
    }

    @Override
    public void setValueAt(Object aValue, int row, int column) {
        super.setValueAt(aValue, row, column);
        if (column < 2) {
            Integer qty = (Integer)getValueAt(row, 0);
            Double price = (Double)getValueAt(row, 1);
            Double amt = (qty != null && price != null) 
                       ? (Double)(qty * price)
                       : null;
            super.setValueAt(amt, row, 2);
        }
    }
};

有关示例的一些注释:

  1. 在此示例中,我仅设置了实际重要的三列:qtypriceamt
  2. 只有 qtyprice 列可编辑,而 amt 不可编辑(在其他列更新时计算)。
  3. 考虑到 getColumnClass() 实现,默认编辑器不允许任何数字列的无效输入:无论列类是 Integer,它都只允许整数值。这同样适用于 Double 类。
  4. 如果qtyprice 列被修改,则调用setValueAt(...)amt专栏也相应更新。

最后,为了在渲染单元格(未编辑)时应用货币格式,我们需要提供一个自定义渲染器。例如:

class CurrencyRenderer extends DefaultTableCellRenderer {

    private final NumberFormat currencyFormat;

    public CurrencyRenderer() {
        currencyFormat = NumberFormat.getCurrencyInstance();
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        Component renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        if (value instanceof Number) {
            setText(currencyFormat.format((Number)value));
        }
        return renderer;
    }
}

现在,有不同的方法来提供渲染器,所有解释都在这里:Concepts: Editors and Renderers

关于java - JTable 上的自定义单元格返回错误值(并且无法正确显示),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27301223/

相关文章:

java - 如何安排任务运行一次?

java - 如何随着每个级别增加数组列表中的敌人数量?

java - 如何检查 Android 设备中的 voLTE 功能?

java - 将 Action 监听器添加到 RadioPanel

java - 如何从mysql获取数据到jList?

java - Java Swing 的 JTable 样式或主题

Java 错误方法未定义 Echo 类型

java - 是否有 JGoodies FormLayout 和 DefaultFormBuilder 的 JavaFX 等价物?

java - 创建一个最初为空但允许用户动态添加行的 Java 表模型

java - JTable日历模型