JFormattedTextField non è stato correttamente cancellato

Sto facendo questo incarico, faccio un programma che risolve il sudoku. Ho un pannello con una griglia di SudokuTextBox estende JFormattedTextField. Ho un MaskFormatter in modo che accetti solo un numero intero per casella di testo. Poi nel mio pannello ho questo codice quando viene rinviata una chiave.

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(); } 

Il fatto è che se metto un valore valido in una casella di testo, allora torno indietro e inserisco un valore non valido (secondo le regole di sudoku) la casella di testo è deselezionata. Ma poi quando passo avanti il ​​valore valido precedente viene visualizzato nella casella di testo. La mia sudokumatrix che contiene tutti i numeri che sono stati inseriti cancella il valore come dovrebbe, quindi è solo nella casella di testo corrispondente.

Per rendere le cose ancora più confuse quando cambio “SudokuTextBox estende JFormattedTextField” a “SudokuTextBox estende JTextField” funziona come un incantesimo. Ma non posso impostare la dimensione di JTextField in modo che sia quadrata e non posso applicare solo un numero intero per casella di testo.

Mi manca qualcosa di veramente ovvio?

    Ecco un esempio di un componente ridimensionabile che potrebbe essere adatto per un gioco del genere. Sebbene non contenga alcuna logica di gioco, gestisce l’input abbastanza bene. Facendo clic con il mouse o premendo la barra spaziatrice, si apre un menu e i tasti Tab e Numero funzionano come previsto. In particolare, Digit.EMPTY è un valore valido.

    alt text

     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 actionPerformsd(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 actionPerformsd(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 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; } } 

    Ok così ora ho trovato, “Uno dei difetti del formattatore di maschere è che a partire dall’attuale implementazione (Java 5), ​​non ha alcun supporto per consentire a un utente di ripristinare un campo al valore vuoto (il valore iniziale del campo prima di qualsiasi input dell’utente) una volta che hanno lasciato il campo in qualsiasi punto. ”

    Quindi dal momento che sto usando un MaskFormatter non posso cancellare il campo.

    Anche se non la stessa domanda, stavo cercando tra le (troppe) domande come questa. Nel mio caso volevo essere in grado di riempire altri due campi (jtfStarePatReq e jtfStarePatFound che sono JTextFields) o cercando direttamente un indice o usando alcuni spinners e creando una stringa e poi guardando quella stringa in alto (okay, forse è troppo vago ma penso che sia abbastanza contesto). Quello che volevo è che se l’utente cancellasse o cancellasse il valore in JFormattedTextField jftfStareOpsIndex, anche gli altri due campi sarebbero stati cancellati. Stavo usando il metodo .isEmpty () su JFormattedTextField per decidere se dovrei usare quel campo O usare il metodo di ricerca calcolato più lungo. Quindi ho bisogno che sia vuoto se qualcuno passa dal cercare il proprio indice per permettere al software di cercare l’indice. Ad ogni modo, ho provato a catturare l’eccezione commitEdit () e impostare il valore su null e sembra che faccia il trucco.

     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); } } } }