JFormattedTextField не очищен должным образом - PullRequest
2 голосов
/ 10 ноября 2010

Я делаю это задание, создаю программу, которая решает судоку. У меня есть панель с сеткой 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();
 }

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

Чтобы сделать вещи еще более запутанными, когда я меняю "SudokuTextBox расширяет JFormattedTextField" на "SudokuTextBox расширяет JTextField", он работает как шарм. Но я не могу установить размер JTextField, чтобы он был квадратным, и я не могу применить только одно целое число в текстовом поле.

Я что-то упускаю действительно очевидное?

Ответы [ 3 ]

6 голосов
/ 11 ноября 2010

Вот пример изменяемого размера компонента, который может подойти для такой игры.Хотя он не содержит игровой логики, он достаточно хорошо обрабатывает ввод.Если щелкнуть мышью или нажать клавишу пробела, появится всплывающее меню, и клавиши табуляции и числа будут работать, как и ожидалось.В частности, 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;
    }
}
2 голосов
/ 10 ноября 2010

Хорошо, теперь я нашел это: «Одним из недостатков средства форматирования маски является то, что в текущей реализации (Java 5) он не поддерживает разрешение пользователю возвращать поле в пустое значение (начальное значение). поля перед любым пользовательским вводом) после того, как они покинули поле в любой точке. "

Так что, поскольку я использую MaskFormatter, я не могу очистить поле.

0 голосов
/ 24 июля 2013

Хотя вопрос не был идентичным, я искал (слишком много) таких вопросов, как этот. В моем случае я хотел иметь возможность заполнить два других поля (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);
            }
        }
    }
}
...