欢迎创建我自己的Swing组件的建议

时间:2010-03-24 20:47:02

标签: java swing bigdecimal

最近I asked是绑定到BigDecimal变量的最佳Swing组件(具有一些特定的编辑属性)。事实证明,没有一个标准的Swing组件完全适合我,也没有找到我发现的第三方Swing组件库。所以我决定创建自己的Swing组件。

组件说明:

我想扩展JTextFieldJFormattedTextField,因此我的新组件可以轻松绑定到BigDecimal变量。

该组件将具有可自定义的比例长度属性。

行为:

绘制组件时,它仅显示右侧 scale 数字的小数点和空格。

当组件获得焦点时,插入符号应位于小数点左侧。当用户键入数字(忽略任何其他字符)时,它们出现在插入符的左侧,只接受 length - scale 数字,任何其他键入的数字都将被忽略为整数部分已满。每当用户键入小数点时,插入符号移动到小数点的右侧。键入的以下数字显示在小数部分,只有 scale 数字被认为是任何其他数字类型被忽略,因为小数部分已满。此外,当用户键入小数点左侧的数字时,应显示千位分隔符。

我还希望能够在Cell Editor中将该组件用作JTable(无需对其进行两次编码)。

在组件上调用getValue()方法应该产生表示刚刚输入的数字的BigDecimal。


我从未创建过自己的Swing组件;我几乎没有使用标准的。所以我很感激有关创建所描述组件的任何好的教程/信息/提示。 This是迄今为止我唯一得到的。

提前致谢。

2 个答案:

答案 0 :(得分:3)

我喜欢你引用的Grouchnikov文章,但我不确定你是否想要更改UI代理。因为这将是一个不可变对象的视图,我赞成组合而不是继承。我倾向于将您描述的组件视为renderer,如此example中所示。您可以添加InputVerifierDocumwntListener以获得所需的验证。

附录:以下是使用JFormattedTextFieldMaskFormatter的示例。您需要调整格式掩码以匹配您的比例和长度。

public class TableGrid extends JPanel {

    private DecimalFormat df;
    private MaskFormatter mf;
    private JFormattedTextField tf;

    public TableGrid() {
        df = new DecimalFormat("0.00");
        try {
            mf = new MaskFormatter("#.##");
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        tf = new JFormattedTextField(mf);
        TableModel dataModel = new TableModel();
        JTable table = new JTable(dataModel);
        table.setCellSelectionEnabled(true);
        table.setRowHeight(32);
        table.setDefaultRenderer(BigDecimal.class, new DecRenderer(df));
        table.setDefaultEditor(BigDecimal.class, new DecEditor(tf, df));
        this.add(table);
    }

    private static class TableModel extends AbstractTableModel {

        private static final int SIZE = 4;
        private BigDecimal[][] matrix = new BigDecimal[SIZE][SIZE];

        public TableModel() {
            for (Object[] row : matrix) {
                Arrays.fill(row, BigDecimal.valueOf(0));
            }
        }

        @Override
        public int getRowCount() {
            return SIZE;
        }

        @Override
        public int getColumnCount() {
            return SIZE;
        }

        @Override
        public Object getValueAt(int row, int col) {
            return matrix[row][col];
        }

        @Override
        public void setValueAt(Object value, int row, int col) {
            matrix[row][col] = (BigDecimal) value;
        }

        @Override
        public Class<?> getColumnClass(int col) {
            return BigDecimal.class;
        }

        @Override
        public boolean isCellEditable(int row, int col) {
            return true;
        }
    }

    private static class DecRenderer extends DefaultTableCellRenderer {

        DecimalFormat df;

        public DecRenderer(DecimalFormat df) {
            this.df = df;
            this.setHorizontalAlignment(JLabel.CENTER);
            this.setBackground(Color.lightGray);
            this.df.setParseBigDecimal(true);
        }

        @Override
        protected void setValue(Object value) {
            setText((value == null) ? "" : df.format(value));
        }
    }

    private static class DecEditor extends DefaultCellEditor {

        private JFormattedTextField tf;
        private DecimalFormat df;

        public DecEditor(JFormattedTextField tf, DecimalFormat df) {
            super(tf);
            this.tf = tf;
            this.df = df;
            tf.setHorizontalAlignment(JFormattedTextField.CENTER);
        }

        @Override
        public Object getCellEditorValue() {
            try {
                return new BigDecimal(tf.getText());
            } catch (NumberFormatException e) {
                return BigDecimal.valueOf(0);
            }
        }

        @Override
        public Component getTableCellEditorComponent(JTable table,
            Object value, boolean isSelected, int row, int column) {
            tf.setText((value == null) ? "" : df.format((BigDecimal) value));
            if (isSelected) tf.selectAll();
            return tf;
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame("TableGrid");
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.add(new TableGrid());
                f.pack();
                f.setVisible(true);
            }
        });
    }
}

答案 1 :(得分:2)

使用您喜欢的任何组件并注册KeyListener以拒绝符合您行为的字符。添加getValue()&amp; setValue可以轻松获取/设置BiDecimal和其他一些方法,所有绘画都将由任何JTextComponent提供。