2010-11-10 3 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(); 
} 

Дело в том, если я ставлю действительное значение в текстовом поле, а затем я вернуться назад и ввести недопустимое значение (по правилам судоку) текстовое поле очищается. Но затем, когда я нажимаю вперед, предыдущее действительное значение отображается в текстовом поле. Моя судокуматрица, содержащая все введенные числа, очищает значение, как должно, поэтому оно находится только в соответствующем текстовом поле.

Чтобы еще больше сбить с толку, когда я изменяю «SudokuTextBox расширяет JFormattedTextField» до «SudokuTextBox extends 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

+0

@refuser: проблем нет; Я изучал ключевые привязки. – trashgod

0

Хотя не тождественны вопрос, я искал через (слишком много) вопросы, как этот. В моем случае я хотел иметь возможность заполнить еще два поля (jtfStarePatReq и jtfStarePatFound, которые являются JTextFields), либо путем поиска индекса напрямую, либо с помощью некоторых прядильщиков, и создания строки, а затем просмотра этой строки (хорошо, может быть, это тоже расплывчатый, но я думаю, что достаточно контекста). Я хотел, чтобы, если пользователь удалил или очистил значение в JFormattedTextField jftfStareOpsIndex, тогда остальные два поля также будут очищены. Я использовал метод .isEmpty() на JFormattedTextField, чтобы решить, следует ли мне использовать это поле или использовать более длинный вычисленный метод поиска. Поэтому мне НЕОБХОДИМО быть пустым, если кто-то идет от поиска своего индекса, чтобы позволить поиску программного обеспечения для индекса. В любом случае, я попытался поймать исключение 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); 
      } 
     } 
    } 
}