JComboBox选择后JTextField占位文本恢复及DocumentFilter兼容问题
技术问题:JComboBox选择后JTextField清除与占位文本异常处理
用户选择JComboBox选项后,无法正确清除JTextField的输入内容。原因是JTextField绑定了限制输入长度的DocumentFilter,导致setText("")方法失效。临时解决方案是先将JTextField设置为PlainDocument,清除输入后重新添加过滤器,但这会导致占位文本无法立即显示,只有点击字段后才会出现(占位文本通过FocusListener实现)。
现有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库,但清除输入后用户再次输入时,提示文本会停留在输入内容后方;
- 考虑过SwingX库的PromptSupport,但该库已停止维护。
当前实现存在占位文本显示/消失不稳定的问题,以下是可复现的完整示例代码:
可复现示例代码(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 { /** * 允许输入的字符数量 */ private final int length; /** * 根据指定长度限制输入字符数量 * * @param length 允许输入的字符数量 */ 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; } }
内容的提问来源于stack exchange,提问作者righN
相关产品推荐
相关产品推荐

