JFormattedTextField未正确清除

我正在做这个任务,制作一个解决数独的程序。 我有一个SudokuTextBox的网格面板扩展JFormattedTextField。 我有一个MaskFormatter,所以它只接受一个整数每个文本框。 然后在我的面板中,我有这个代码,当一个关键是相关的。

public void keyReleased(KeyEvent e) { SudokuTextBox tb = (SudokuTextBox) e.getSource(); int row = tb.getRow(); int col = tb.getCol(); int value = toInteger(tb.getText()); //System.out.println(value); if(sudoku.isValid(row, col, value)) { sudoku.set(row, col, value); } else { sudoku.set(row, col, 0); tb.setText(null); } tb.setCaretPosition(0); sudoku.print(); } 

事情是,如果我把一个有效的值在一个文本框中,然后我回去并输入一个无效的值(由数独规则)文本框被清除。 但是,当我向前看,前面的有效值显示在文本框中。 包含所有已输入数字的我的sudokumatrix会清除值,因此它只在相应的文本框中显示。

当我将“SudokuTextBox扩展JFormattedTextField”改为“SudokuTextBox扩展JTextField”时,使事情变得更加混乱,就像一个魅力。 但我不能设置JTextField的大小,以便它是正方形,我不能强制每个文本框只有一个整数。

我错过了一些非常明显的东西吗

这是一个可调整的组件的例子,可能适合这样的游戏。 虽然它不包含游戏逻辑,但它处理输入相当好。 点击鼠标或按下空格键弹出菜单,标签和数字键按预期工作。 特别是, Digit.EMPTY是一个有效的值。

替代文字

 import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.util.EnumSet; import javax.swing.*; /** @see http://stackoverflow.com/questions/4148336 */ public class CellTest extends JPanel { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { //@Override public void run() { createGUI(); } }); } public static void createGUI() { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new GridLayout(3, 3)); for (Digit d : Digit.digits) { frame.add(new CellTest(d)); } frame.pack(); frame.setVisible(true); } CellTest(Digit digit) { this.setLayout(new BorderLayout()); this.setBorder(BorderFactory.createLineBorder(Color.black, 1)); this.setBackground(new Color(0x00e0e0)); JLabel candidates = new JLabel("123456789"); candidates.setHorizontalAlignment(JLabel.CENTER); this.add(candidates, BorderLayout.NORTH); JDigit cellValue = new JDigit(digit); add(cellValue, BorderLayout.CENTER); } } class JDigit extends JButton { private static final int SIZE = 128; private static final int BASE = SIZE / 32; private static final Font FONT = new Font("Serif", Font.BOLD, SIZE); private JPopupMenu popup = new JPopupMenu(); private Digit digit; private Image image; private int width, height; public JDigit(Digit digit) { this.digit = digit; this.image = getImage(digit); this.setPreferredSize(new Dimension(64, 64)); this.setBackground(new Color(0xe0e000)); this.setForeground(Color.black); this.setBorderPainted(false); this.setAction(new ButtonAction()); this.addFocusListener(new FocusHandler()); for (Digit d : Digit.values()) { Action select = new SelectAction(d); JMenuItem item = new JMenuItem(select); getInputMap().put(KeyStroke.getKeyStroke( KeyEvent.VK_0 + d.value(), 0), d.toString()); getInputMap().put(KeyStroke.getKeyStroke( KeyEvent.VK_NUMPAD0 + d.value(), 0), d.toString()); getActionMap().put(d.toString(), select); popup.add(item); } } public Digit getDigit() { return digit; } public void setDigit(Digit digit) { this.digit = digit; this.image = getImage(digit); this.repaint(); } @Override protected void paintComponent(Graphics g) { int w = this.getWidth(); int h = this.getHeight(); g.setColor(this.getBackground()); int dx1 = w * width / height / 4; int dx2 = w - dx1; g.fillRect(dx1, 0, dx2 - dx1, h); g.drawImage(image, dx1, 0, dx2, h, 0, 0, width, height, null); } private Image getImage(Digit digit) { BufferedImage bi = new BufferedImage( SIZE, SIZE, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = bi.createGraphics(); g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(this.getForeground()); g2d.setFont(FONT); FontMetrics fm = g2d.getFontMetrics(); width = fm.stringWidth(digit.toString()); height = fm.getAscent(); g2d.drawString(digit.toString(), 0, height - BASE); g2d.dispose(); return bi; } private class ButtonAction extends AbstractAction { //@Override public void actionPerformed(ActionEvent e) { popup.show(JDigit.this, getWidth() - width, getHeight() / 2); } } private class SelectAction extends AbstractAction { private Digit digit; public SelectAction(Digit digit) { this.digit = digit; this.putValue(Action.NAME, digit.toString()); } //@Override public void actionPerformed(ActionEvent e) { setDigit(digit); } } private class FocusHandler implements FocusListener { private Color background = getBackground(); //@Override public void focusGained(FocusEvent e) { setBackground(background.brighter()); } //@Override public void focusLost(FocusEvent e) { setBackground(background); } } } enum Digit { EMPTY(0, " "), ONE(1, "1"), TWO(2, "2"), THREE(3, "3"), FOUR(4, "4"), FIVE(5, "5"), SIX(6, "6"), SEVEN(7, "7"), EIGHT(8, "8"), NINE(9, "9"); public static EnumSet<Digit> digits = EnumSet.range(Digit.ONE, Digit.NINE); private int i; private String s; Digit(int i, String s) { this.i = i; this.s = s; } @Override public String toString() { return s; } public int value() { return i; } } 

好吧,现在我发现它,“掩码格式化程序的一个缺点是,从当前的实现(Java 5),它不支持让用户将字段还原为空值(字段的初始值在任何用户输入之前),一旦他们离开了任何一点的领域。

所以,因为我使用的MaskFormatter我不能清除该字段。

虽然不是同一个问题,但我正在寻找这样一个(太多)的问题。 在我的情况下,我想要能够填充两个其他字段(jtfStarePatReq和jtfStarePatFound这是JTextFields)通过直接查找索引或通过使用一些spinners和创建一个字符串,然后查找该字符串(好吧,也许这也是含糊不清,但我认为这是足够的上下文)。 我想要的是,如果用户删除或清除了JFormattedTextField jftfStareOpsIndex中的值,那么其他两个字段也将被清除。 我正在使用JFormattedTextField上的.isEmpty()方法来决定是否应该使用该字段或使用较长的计算搜索方法。 所以如果有人从查找自己的索引到让软件搜索索引,我需要它是空的。 无论如何,我试图捕获commitEdit()异常,并将值设置为null,它似乎是伎俩。

 public class stareOpsIndexListener extends KeyAdapter implements FocusListener { public void focusGained(FocusEvent e) { } public void focusLost(FocusEvent e) { try { JFormattedTextField jftf = (JFormattedTextField) e.getComponent(); jftf.commitEdit(); updateStareOpsIndex(jftf); } catch (ParseException ex) { jtfStarePatReq.setText(""); jtfStarePatFound.setText(""); jftfStareOpsIndex.setValue(null); } } public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if (key == KeyEvent.VK_ENTER) { try { JFormattedTextField jftf = (JFormattedTextField) e.getComponent(); jftf.commitEdit(); updateStareOpsIndex(jftf); } catch (ParseException ex) { jtfStarePatReq.setText(""); jtfStarePatFound.setText(""); jftfStareOpsIndex.setValue(null); } } } }