0

私はカスタム POS システムを作成しており、ユーザーがダイアログ ボックスを表示する代わりに、テーブルで直接数量を変更できるようにしています。これは、ダミー データを含むテーブルの最初の行です。(まだDBにリンクしていません。) ここに画像の説明を入力

Price と Amt はどちらも、money 形式を表示するためのカスタム セル レンダラー (正しく表示されないため、誰にもわかりません) を持っています。EDIT:カスタムエディタ(レンダラーではありません、ありがとう)を修正しましたが、以下の問題は引き続き発生します

計画では、ユーザーが数量ボックスに数量を入力すると、金額セル (および画面上部の現在の合計) が更新されるというものでした。これを行うために、データが整数であることを検証するベリファイアを作成し、そのベリファイアを JTextField に追加するだけのカスタム セル エディタにアタッチしました。

画面自体にネストされているため、画面のフィールドとテーブル自体にアクセスできるベリファイア。テーブルモデルに入れたかったのですが、ユーザーがどのセルを選択したのかわかりませんでした。(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;
    }

    ....
};

ここが本当に奇妙になるところです。数量がまだ 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.

私のテーブルで何が起こっているのですか?! これにより、2 つのセルに完全に間違った情報が表示され、qty セルが入力していないものに変更されるのはなぜですか? これを行う簡単な方法はありますか (ベリファイアの有無にかかわらず)? 注文フォームに間違った費用が表示されることはありません。丸めエラーを防ぐために、すべての値を double から BigDecimals に変更することを検討しましたが、これは丸めエラーでもありません。それは単純に間違っています。私は今完全に迷っています。

4

1 に答える 1

2

あなたのコードは高度にカスタマイズされており、すべてのピースをまとめないとデバッグが難しいため、基本的な概念に魅力を感じ、これらの要件はTableModelを使用して満たすことができると言って、ゼロから始めます。

  • 数値列の入力を確認します。テーブル モデルのgetColumnClass(...)が適切なクラスを返す場合、これは適切なエディターに委任できます 。カスタムエディタは必要ありません!
  • amt列の更新qtyまたは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. qtyこの例では、実際に重要な 3 つの列のみを設定しましpriceamt
  2. qtypriceの列のみが編集可能ですが、amtは編集できません (他の列が更新されたときに計算されます)。
  3. 実装を考えるとgetColumnClass()、既定のエディターは数値列のいずれに対しても無効な入力を許可しません。列クラスが Integer であるかどうかにかかわらず、整数値のみを許可します。ダブルクラスも同様です。
  4. いずれか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;
    }
}

現在、レンダラーを提供するさまざまな方法があり、すべてここで説明されています:概念: エディターとレンダラー

于 2014-12-04T19:59:36.487 に答える