2010-11-10 71 views
1

我正在做這個任務,做一個解決數獨的程序。我有一個SudokuTextBox網格擴展JFormattedTextField的面板。我有一個MaskFormatter,因此它只接受每個文本框一個整數。 然後在我的面板中,我有這個代碼,當一個關鍵是相關的。JFormattedTextField沒有正確清除

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的大小,以便它是方形的,我不能強制每個文本框只有一個整數。

我是否錯過了一些非常明顯的東西?

回答

2

好,現在我發現它,「掩碼格式化程序的一個缺點是,從當前實現(Java 5)開始,它不支持讓用戶將字段還原爲空值(初始值任何用戶輸入之前的字段值)一旦他們在任何點離開了該字段。「

所以,因爲我使用MaskFormatter我無法清除該字段。

6

下面是一個可調整組件的例子,可能適合這樣的遊戲。雖然它不包含遊戲邏輯,但它可以很好地處理輸入。單擊鼠標或按下空格鍵彈出菜單,並且標籤和數字鍵按預期工作。特別是,Digit.EMPTY是有效的值。

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 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; 
    } 
} 
+0

對不起,我不接受你的答案。然而,我更感興趣的是爲什麼我無法讓JFormattedTextField做我想做的事,而不是如何推出我自己的組件。雖然謝謝! – evading 2010-11-13 12:03:53

+0

@refuser:沒問題;我正在探索關鍵綁定。 – trashgod 2010-11-13 14:46:18

0

雖然不是同一個問題,我是通過這樣一個(太多)的問題進行搜索。在我的情況下,我希望能夠通過直接查找索引或使用一些spinners並創建一個字符串然後查看該字符串來填充另外兩個字段(jtfStarePatReq和jtfStarePatFound,它們是JTextFields)(好吧,也許這也太過了含糊不清,但我認爲這是足夠的上下文)。我想要的是,如果用戶刪除或清除了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); 
      } 
     } 
    } 
}