这是显示无效用户输入的好方法吗?

时间:2018-01-16 01:26:04

标签: java swing

我想在用户输入无效值的文本字段上设置红色边框。即使用户没有编辑它们,此字段也可能具有无效值,例如DateFormatter上的空值。或NumberFormatter上的空值。这就是我使用FocusListener的原因。

以下是两个可以满足我需要的类,但是,当应用程序在没有用户输入的情况下设置或更改值时,该字段仍然显示为无效。

我不确定我是否应该使用“外观和感觉”作为解决方案,或者“行动”。在我试图实现这种需求的方式上,您是否看到了良好的OOP方法?

提前致谢。

public class Form {
    private java.util.ArrayList<JComponent> list = new java.util.ArrayList();
    private TextVerifier verifier;

    public Form() {
        verifier = new TextVerifier();
    }
    public void add(JComponent c) {
        if (c instanceof JFormattedTextField) {
            ((JFormattedTextField)c).setFocusLostBehavior(JFormattedTextField.COMMIT);
            c.addFocusListener(verifier);
        }
    }
    public void clear() {
        for (JComponent c : list) {
            verifier.unmark(c);
        }
    }
}
public class TextVerifier implements FocusListener {
    @Override
    public void focusGained(FocusEvent e) {

    }
    @Override
    public void focusLost(FocusEvent e) {
        if (e.getSource() instanceof JFormattedTextField) {
            JFormattedTextField field = (JFormattedTextField)e.getSource();
            if (isValid(field)) {
                unmark(field);
            }
            else {
                mark(field);
            }
        }
    }
    public void mark(JComponent component) {
        if (component!=null) {
            component.setBorder(javax.swing.BorderFactory.createLineBorder(java.awt.Color.red, 1));
        }            
    }
    public void unmark(JComponent component) {
        if (component!=null) {
            component.setBorder(null);
        }
    }

    public boolean isValid(JFormattedTextField field) {
        JFormattedTextField.AbstractFormatter formatter = field.getFormatter();
        if (formatter != null) {
            try {
                formatter.stringToValue(field.getText());
            }
            catch (java.text.ParseException e) {
                return false;
            }
        }
        return true;
    }
}

1 个答案:

答案 0 :(得分:0)

我更喜欢使用DocumentListener。为了解决您的问题,我认为这将是最好的方法。 请注意TextVerifier中的mark和unmark方法,以避免lookAndFeel出现问题,只更改文本字段的背景可能会更好,它看起来比文本字段上的红色边框更好。

    public void add(JComponent c) {
        if (c instanceof JFormattedTextField) {
            ((JFormattedTextField) c).setFocusLostBehavior(JFormattedTextField.COMMIT);
            c.addFocusListener(verifier);
                            //Add the component to the document properties
            ((JFormattedTextField) c).getDocument().putProperty("owner", c);
                            //Change Verifier to implement DocumentListener. You wouldn't need focusListener in this case.
            ((JFormattedTextField) c).getDocument().addDocumentListener(verifier);
            list.add(c);
        }
    }

以下完整代码:

import java.awt.BorderLayout;
import java.util.Random;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.NumberFormatter;

public class Form {
    private java.util.ArrayList<JComponent> list = new java.util.ArrayList<>();
    private TextVerifier verifier;

    public Form() {
        verifier = new TextVerifier();
    }

    public void add(JComponent c) {
        if (c instanceof JFormattedTextField) {
            ((JFormattedTextField) c).setFocusLostBehavior(JFormattedTextField.COMMIT);
            c.addFocusListener(verifier);
            ((JFormattedTextField) c).getDocument().putProperty("owner", c);
            ((JFormattedTextField) c).getDocument().addDocumentListener(verifier);
            list.add(c);
        }
    }

    public void clear() {
        for (JComponent c : list) {
            verifier.unmark(c);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        frame.getContentPane().add(panel, BorderLayout.CENTER);
        Form form = new Form();
        for (int i = 0; i < 5; i++) {
            JLabel label = new JLabel("Number " + i + ": ");
            JFormattedTextField field = new JFormattedTextField(new NumberFormatter());
            panel.add(createLabelFieldPanel(label, field));
            form.add(field);
        }

        JButton change = new JButton("Change");
        change.addActionListener(e -> form.updateValues());

        frame.getContentPane().add(change, BorderLayout.SOUTH);
        frame.pack();
        form.updateValues();
        frame.setVisible(true);
    }

    private Random random = new Random();

    private void updateValues() {
        for (JComponent c : list) {
            if (c instanceof JFormattedTextField) {
                ((JFormattedTextField) c).setValue(random.nextInt(100));
            }
        }
    }

    public static JPanel createLabelFieldPanel(final JComponent label, final JComponent field) {
        final JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
        panel.add(label);
        panel.add(field);
        return panel;
    }
}

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class TextVerifier implements FocusListener, DocumentListener {
    @Override
    public void focusGained(FocusEvent e) {

    }

    @Override
    public void focusLost(FocusEvent e) {
        if (e.getSource() instanceof JFormattedTextField) {
            JFormattedTextField field = (JFormattedTextField) e.getSource();
            if (isValid(field)) {
                unmark(field);
            } else {
                mark(field);
            }
        }
    }

private static final Color RED = hex2Rgb("fffeeeddd");

public static Color hex2Rgb(String colorStr) {
    return new Color(
            Integer.valueOf( colorStr.substring( 1, 3 ), 16 ),
            Integer.valueOf( colorStr.substring( 3, 5 ), 16 ),
            Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) );
}

public void mark(JComponent component) {
    if (component != null) {
        component.setBackground(RED);
    }
}

public void unmark(JComponent component) {
    if (component != null) {
        component.setBackground(Color.white);
    }
}

    public boolean isValid(JFormattedTextField field) {
        JFormattedTextField.AbstractFormatter formatter = field.getFormatter();
        if (formatter != null) {
            try {
                formatter.stringToValue(field.getText());
            } catch (java.text.ParseException e) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
        docChanged(e);
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        docChanged(e);
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
        docChanged(e);
    }

    private void docChanged(DocumentEvent e) {
        if (e.getDocument().getProperty("owner") instanceof JFormattedTextField) {
            JFormattedTextField field = (JFormattedTextField) e.getDocument().getProperty("owner");
            if (isValid(field)) {
                unmark(field);
            } else {
                mark(field);
            }
        }
    }
}