最近I asked是绑定到BigDecimal变量的最佳Swing组件(具有一些特定的编辑属性)。事实证明,没有一个标准的Swing组件完全适合我,也没有找到我发现的第三方Swing组件库。所以我决定创建自己的Swing组件。
我想扩展JTextField或JFormattedTextField,因此我的新组件可以轻松绑定到BigDecimal变量。
该组件将具有可自定义的比例和长度属性。
绘制组件时,它仅显示右侧 scale 数字的小数点和空格。
当组件获得焦点时,插入符号应位于小数点左侧。当用户键入数字(忽略任何其他字符)时,它们出现在插入符的左侧,只接受 length - scale 数字,任何其他键入的数字都将被忽略为整数部分已满。每当用户键入小数点时,插入符号移动到小数点的右侧。键入的以下数字显示在小数部分,只有 scale 数字被认为是任何其他数字类型被忽略,因为小数部分已满。此外,当用户键入小数点左侧的数字时,应显示千位分隔符。
我还希望能够在Cell Editor中将该组件用作JTable(无需对其进行两次编码)。
在组件上调用getValue()方法应该产生表示刚刚输入的数字的BigDecimal。
我从未创建过自己的Swing组件;我几乎没有使用标准的。所以我很感激有关创建所描述组件的任何好的教程/信息/提示。 This是迄今为止我唯一得到的。
提前致谢。
答案 0 :(得分:3)
我喜欢你引用的Grouchnikov文章,但我不确定你是否想要更改UI代理。因为这将是一个不可变对象的视图,我赞成组合而不是继承。我倾向于将您描述的组件视为renderer,如此example中所示。您可以添加InputVerifier
或DocumwntListener
以获得所需的验证。
附录:以下是使用JFormattedTextField
和MaskFormatter
的示例。您需要调整格式掩码以匹配您的比例和长度。
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提供。