我遇到了问题。当用户在
JTextField
中进行选择后,我真的无法弄清楚如何正确清除 JComboBox
中的用户输入。每个 DocumentFilter
添加了一个 JTextField
用于限制最大输入长度,因此它有点破坏 setText("")
变体,因为虽然设置了 DocumentFilter
,但它不起作用。我通过将 JTextField
设置为 PlainDocument
,清除输入,然后重新添加过滤器来解决这个问题。现在的问题是,除非我单击该字段,否则占位符文本不会重新出现。我使用 FocusListener
添加该提示,所以我明白为什么它在单击后再次出现,但是如何在 JComboBox
中进行选择后再次出现该占位符文本?
我的
FocusListener
:
public static class PlaceHolderText implements FocusListener {
private final JTextField field;
private final String placeHolder;
private final Document defaultDocument;
public PlaceHolderText(JTextField field, String placeHolder, Document defaultDocument) {
this.field = field;
this.placeHolder = placeHolder;
this.defaultDocument = defaultDocument;
}
@Override
public void focusGained(FocusEvent e) {
if (field.getText().equals(placeHolder)){
field.setDocument(defaultDocument);
field.setText("");
}
}
@Override
public void focusLost(FocusEvent e) {
if (field.getText().isEmpty()) {
field.setDocument(defaultDocument);
field.setText(placeHolder);
}
}
}
清除输入:
private void recreateTextFields() {
titleField.setDocument(new PlainDocument());
titleField.setText("");
((AbstractDocument)titleField.getDocument()).setDocumentFilter(inputLength);
priceField.setDocument(new PlainDocument());
priceField.setText("");
((AbstractDocument)priceField.getDocument()).setDocumentFilter(numericAndLengthPrice);
pointsField.setDocument(new PlainDocument());
pointsField.setText("");
((AbstractDocument)pointsField.getDocument()).setDocumentFilter(numericAndLengthPoints);
}
JComboBox
中的选择之一:
else if ("Property".equals(selectedItem)) {
typeChosen = true;
propertyCardChosen = true;
if (cardInstanceCreated) {
remove(cardInstance);
cardInstanceCreated = false;
}
recreateTextFields();
add(createCard(), "pos 950px 120px");
revalidate();
repaint();
我尝试使用 [TextPrompt][1] 库,但清除输入后并且当用户输入其他内容时,提示仅保留在用户输入后面。我考虑过使用 SwingX 库的
PromptSupport
,但据我所知,SwingX 不再受支持。
MRE(包括文档过滤器之一)
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
public class MRE extends JFrame {
private JPanel pnlMenu;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MRE app = new MRE();
}
});
}
private MRE() {
setLayout(new BorderLayout());
create();
add(pnlMenu, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1600, 1000);
setVisible(true);
setResizable(false);
}
private JPanel create() {
pnlMenu = new JPanel();
String placeHolder = "PlaceHolder";
JTextField field = new JTextField(placeHolder);
Document defaultDocument = field.getDocument();
field.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (field.getText().equals(placeHolder)) {
field.setDocument(defaultDocument);
field.setText("");
}
}
@Override
public void focusLost(FocusEvent e) {
if (field.getText().isEmpty()) {
field.setText(placeHolder);
}
}
});
field.setPreferredSize(new Dimension(260, 40));
((AbstractDocument)field.getDocument()).setDocumentFilter(new NumericAndLengthFilter(2));
String[] choicesString = { "1", "2" };
JComboBox choices = new JComboBox(choicesString);
choices.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent event) {
if (event.getStateChange() == ItemEvent.SELECTED) {
Object source = event.getSource();
if (source instanceof JComboBox) {
@SuppressWarnings("unchecked")
JComboBox<String> cb = (JComboBox<String>) source;
Object selectedItem = cb.getSelectedItem();
if ("1".equals(selectedItem)) {
field.setDocument(defaultDocument);
field.setText("");
((AbstractDocument)field.getDocument()).setDocumentFilter(new NumericAndLengthFilter(2));
revalidate();
repaint();
}
if ("2".equals(selectedItem)) {
field.setDocument(defaultDocument);
field.setText("");
((AbstractDocument)field.getDocument()).setDocumentFilter(new NumericAndLengthFilter(2));
revalidate();
repaint();
}
}
}
}
});
pnlMenu.add(field);
pnlMenu.add(choices);
return pnlMenu;
}
public static class NumericAndLengthFilter extends DocumentFilter {
/**
* Number of characters allowed.
*/
private final int length;
/**
* Restricts the number of charcacters can be entered by given length.
*
* @param length Number of characters allowed.
*/
public NumericAndLengthFilter(int length) {
this.length = length;
}
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (isNumeric(string)) {
if (this.length > 0 && fb.getDocument().getLength() + string.length() > this.length) {
return;
}
super.insertString(fb, offset, string, attr);
}
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (isNumeric(text)) {
if (this.length > 0 && fb.getDocument().getLength() + text.length() > this.length) {
return;
}
super.insertString(fb, offset, text, attrs);
}
}
}
public static boolean isNumeric(String text) {
if (text == null || text.trim().isEmpty()) {
return false;
}
for (int iCount = 0; iCount < text.length(); iCount++) {
if (!Character.isDigit(text.charAt(iCount))) {
return false;
}
}
return true;
}
}
老实说,即使这个实现也有问题,占位符文本并不总是消失甚至出现。
我使用 TextPrompt 类时没有问题:
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
public class IntegerFilter extends DocumentFilter
{
@Override
public void insertString(FilterBypass fb, int offset, String text, AttributeSet attributes)
throws BadLocationException
{
replace(fb, offset, 0, text, attributes);
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attributes)
throws BadLocationException
{
// In case someone tries to clear the Document by using setText(null)
if (text == null)
text = "";
// Build the text string assuming the replace of the text is successfull
Document doc = fb.getDocument();
StringBuilder sb = new StringBuilder();
sb.append(doc.getText(0, doc.getLength()));
sb.replace(offset, offset + length, text);
if (validReplace(sb.toString()))
super.replace(fb, offset, length, text, attributes);
else
Toolkit.getDefaultToolkit().beep();
}
private boolean validReplace(String text)
{
// In case setText("") is used to clear the Document
if (text.isEmpty())
return true;
// Verify input is an Integer
try
{
Integer.parseInt( text );
// Double.parseDouble( text );
return true;
}
catch (NumberFormatException e)
{
return false;
}
}
private static void createAndShowGUI()
{
JTextField textField = new JTextField(4);
AbstractDocument doc = (AbstractDocument) textField.getDocument();
doc.setDocumentFilter( new IntegerFilter() );
textField.setText("123");
// textField.setText("123567");
// textField.setText(null);
TextPrompt tp = new TextPrompt("Enter Day:", textField);
JButton clear = new JButton("Clear");
clear.addActionListener((e) -> textField.setText(""));
JFrame frame = new JFrame("Integer Filter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(textField, BorderLayout.PAGE_START);
frame.add(clear, BorderLayout.PAGE_END);
frame.setSize(220, 200);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
我会让您修改过滤器以限制数字。
对 DocumentFilter 的评论: