我正在编写一个自定义POS系统,允许用户直接在桌面上更改数量,而不是生成一个对话框。这是表格的第一行,其中包含虚拟数据。 (我还没把它与数据库联系起来。)
Price和Amt都有自定义单元格渲染器(不是任何人都可以告诉,因为它们不能正确渲染)以显示货币格式。编辑:我添加了自定义编辑器(不是渲染器,谢谢),下面的问题仍然存在
计划是当用户在数量框中输入数量时,它会更新amt单元格(以及屏幕顶部的运行总计)。为此,我创建了一个验证程序,用于验证数据是否为整数,并将其附加到自定义单元格编辑器,该编辑器只是将验证程序添加到JTextField。
我的验证器嵌套在屏幕本身内,因此它可以访问屏幕的字段和表格本身。我想把它放到表模型中,但我发现我无法告诉用户选择了哪个单元格。 (验证()有效,所以我省略了)
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;
}
....
};
这里真的很奇怪。我告诉数量,数量仍然是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键。
它将值更改为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.
我的桌子怎么了?!为什么这会在两个单元格中给出完全错误的信息并将qty单元格更改为我没有输入的内容?有没有更简单的方法(使用或不使用验证程序)?我不能在订单上出现错误的费用。我考虑将所有值从双打更改为BigDecimals以防止舍入错误,但这甚至不是舍入错误。这是完全错误的。我现在完全失去了。
答案 0 :(得分:2)
鉴于您的代码是高度自定义的,并且在没有将所有部分组合在一起的情况下难以调试,我从头开始诉诸于基本概念,并说使用TableModel可以满足这些要求:
amt
或qty
列上的price
列更新:这也可以使用表模型完成,只需要正确覆盖setValueAt(...)。price
和amt
列:这可以通过提供自定义渲染器(而不是编辑器)来完成。由于没有关于您的桌面型号的信息,我将使用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);
}
}
};
关于这个例子的一些注释:
qty
,price
和amt
。qty
和price
列可编辑而amt
不可编辑(在其他列更新时计算)。getColumnClass()
实现,默认编辑器不允许任何数字列的无效输入:列类是否为Integer,它只允许整数值。这同样适用于Double class。qty
或price
列,则会调用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