编辑 - 在帖子的最后添加了我们能够实现的答案
这是我在SO的第一篇文章,所以我希望我可以一切正确!
我搜索过,虽然发布了类似的问题,但我的问题并没有找到答案,所以我希望这不是转发。
这就是ai得到的,一个使用JTextField
来接收用户输入的小应用程序,最重要的是我有一个DocumentFilter
所以用户只能输入整数和一个句点来接收表示重量的值。
我的问题是,我的DocumentFilter
我无法过滤“复制粘贴”文字,我无法过滤所选的文字删除。
以下是过滤器的代码
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
/**
* The Class IntAndDotFilter.
*/
public class IntAndDotFilter extends DocumentFilter {
/** The period counter. */
private int periodCounter = 0;
/** The number counter. */
private int numberCounter = 0;
private boolean canRemove = true;
public void setCanRemove(boolean canRemove) {
this.canRemove = canRemove;
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text,
AttributeSet attrs) throws BadLocationException {
if (periodCounter == 0) { // If there is no . on the text
if (text.matches("\\.")) { // Checks if the input is a dot
super.replace(fb, offset, length,
text.replaceAll("[^0-9.]", ""), attrs);
periodCounter++; // If it is, inserts it and saves that info
} else {
super.replace(fb, offset, length,
text.replaceAll("[^0-9]", ""), attrs);
// If not, checks if the input is a digit
// and inserts if it is
}
} else { // If there is already a .
if (text.matches("\\.")) { // Checks if the input is another .
super.replace(fb, offset, length,
text.replaceAll("[^0-9]", ""), attrs);
// If it is, filters so that cannot be more than one .
} else {
if (text.matches("[0-9]")) { // Checks if it's a digit
if (numberCounter != 2) {
super.replace(fb, offset, length,
text.replaceAll("[^0-9]", ""), attrs);
numberCounter++;
// If yes, and if that is only the second one (0.00)
// inserts and
// saves the info that there are digits after the 1st .
// for removal purposes
} else {
super.replace(fb, offset, length,
text.replaceAll(".", ""), attrs);
// if it is the third+ digit after . , doesn't allow the
// input
}
} else {
super.replace(fb, offset, length, text.replaceAll(".", ""),
attrs);
// Not being a digit, doesn't allow the
// insertion of the given input
}
}
}
}
@Override
public void remove(FilterBypass fb, int offset, int length)
throws BadLocationException {
if (canRemove) {
if (periodCounter == 1) { // If there is a . in the text
if (numberCounter != 0) { // and If there are digits after the .
numberCounter--; // It means you'r removing a digit, so it
// saves
// that info
super.remove(fb, offset, length); // And removes it
} else { // If there are no digits it means you'r removing a .
periodCounter--; // It saves that info allowing a new . to
// be
// inserted
super.remove(fb, offset, length); // and removes it
}
} else { // If there is no . in the text there are no problems
super.remove(fb, offset, length); // so it just removes whatever
// there is (digit)
}
} else {
}
}
}
insertString方法与replace方法相同,所以我把它遗漏了,但是在应用程序中它实现了。
提前感谢您的时间!
编辑 - 此外它现在还有一个过滤器来抑制高度输入
public class IntAndDotFilter extends DocumentFilter {
/** The Constant _maxCharacters. */
private static final int _maxCharacters = 10;
/** The _is weight. */
private Boolean _isWeight = null;
public IntAndDotFilter(Boolean isWeight) {
super();
_isWeight = isWeight;
}
public void replace(FilterBypass fb, int offset, int length, String string,
AttributeSet attr) throws BadLocationException {
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
text += string;
if (_isWeight) {
if ((fb.getDocument().getLength() + string.length() - length) <= _maxCharacters
&& text.matches("^[1]?[0-9]{1,2}([.][0-9]{0,2})?$")) {
super.replace(fb, offset, length, string, attr);
} else {
Toolkit.getDefaultToolkit().beep();
}
} else {
if ((fb.getDocument().getLength() + string.length() - length) <= _maxCharacters
&& text.matches("^([1]([.][0-9]{0,2})?)|([2]([.][0-5]?)?)$")) {
super.replace(fb, offset, length, string, attr);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}
@Override
public void remove(FilterBypass fb, int offset, int length)
throws BadLocationException {
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
if (_isWeight) {
if (text.matches("^[1]?[0-9]{1,2}([.][0-9]{0,2})?$")) {
super.remove(fb, offset, length);
} else {
Toolkit.getDefaultToolkit().beep();
}
} else {
if (text.matches("^([1]([.][0-9]{0,2})?)|([2]([.][0-5]?)?)$")) {
super.remove(fb, offset, length);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
}
答案 0 :(得分:10)
你使过滤变得比以前更加复杂。对于插入(如果代码是相同的替换),您可能无法输入,因为\\.
检查。您只能粘贴句点,因为这是您要检查的内容。至于删除,以下建议将适用。
为简化起见,您应该只获取文档的整个文本,然后使用正则表达式检查整个文档字符串是否与正则表达式匹配。它比你想做的要简单得多。您可以很好地解释过滤过程here。
这是一个例子,只使用insertString和replace。对于删除,它没有什么不同,只需获取文本,并检查它是否与正则表达式匹配。我从上面的链接中的答案中获取了部分示例。场景是OP想要最大字符,只允许一个小数位。这就是正则表达式匹配的东西。但也可以在您键入或插入时匹配任何内容,例如00
00.
00.0
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class FilterDemo {
public FilterDemo() {
JFrame frame = new JFrame();
frame.setLayout(new GridBagLayout());
frame.setSize(300, 300);
frame.add(createFilteredField());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public JTextField createFilteredField() {
JTextField field = new JTextField();
AbstractDocument document = (AbstractDocument) field.getDocument();
final int maxCharacters = 10;
document.setDocumentFilter(new DocumentFilter() {
public void replace(FilterBypass fb, int offs, int length,
String str, AttributeSet a) throws BadLocationException {
String text = fb.getDocument().getText(0,
fb.getDocument().getLength());
text += str;
if ((fb.getDocument().getLength() + str.length() - length) <= maxCharacters
&& text.matches("^[0-9]+[.]?[0-9]{0,1}$")) {
super.replace(fb, offs, length, str, a);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
public void insertString(FilterBypass fb, int offs, String str,
AttributeSet a) throws BadLocationException {
String text = fb.getDocument().getText(0,
fb.getDocument().getLength());
text += str;
if ((fb.getDocument().getLength() + str.length()) <= maxCharacters
&& text.matches("^[0-9]+[.]?[0-9]{0,1}$")) {
super.insertString(fb, offs, str, a);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
});
return field;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new FilterDemo();
}
});
}
}
答案 1 :(得分:0)
这是Paul Samsotha's answer的一个版本,已修复了一些错误,并且将正则表达式作为自变量传递以用于更多通用。原始的允许在输入的开头插入或替换无效字符,或者删除导致该字段变为无效的前导字符(它没有实现remove()
。一旦出现无效字符,输入已锁定。
此版本应解决所有这些问题。
示例用法:
// Store the labels and textfields for later retrieval
Vector<JLabel> jLabels = new Vector<JLabel>(8);
Vector<JTextField> jTextFields = new Vector<JTextField>(8);
//Create and populate the panel.
Container contentPane = getContentPane();
// Wrap everything in a BorderLayout
JPanel borderPanel = new JPanel(new BorderLayout());
contentPane.add(borderPanel);
// Put the input fields in the CENTER position
JPanel fieldPanel = new JPanel(new SpringLayout());
borderPanel.add(fieldPanel, BorderLayout.CENTER);
// Put the input fields in the CENTER position
JPanel fieldPanel = new JPanel(new SpringLayout());
borderPanel.add(fieldPanel, BorderLayout.CENTER);
String[] labels = {"Player Name: ", "Initial Chips: "};
String[] filters = {"^[A-Za-z][A-Za-z0-9_ ]*$", "^[1-9][0-9]*$"};
final int numPairs = labels.length;
// Create and associate the field inputs and labels and regex filters
for (int i = 0; i < numPairs; i++) {
JLabel label = new JLabel(labels[i], JLabel.TRAILING);
fieldPanel.add(label);
JTextField textField = createFilteredField(filters[i]);
label.setLabelFor(textField);
fieldPanel.add(textField);
jLabels.add(label);
jTextFields.add(textField);
}
代码:
/* Filtered Text Field
* @param regex
* the regular expression to which this string is to be matched
*
* @return {@code true} if, and only if, this string matches the
* given regular expression
*
* @throws PatternSyntaxException
* if the regular expression's syntax is invalid
*/
public JTextField createFilteredField(String regex) {
JTextField field = new JTextField(12);
AbstractDocument document = (AbstractDocument) field.getDocument();
final int maxCharacters = 20;
document.setDocumentFilter(new DocumentFilter() {
/**
* Invoked prior to removal of the specified region in the
* specified Document. Subclasses that want to conditionally allow
* removal should override this and only call supers implementation as
* necessary, or call directly into the <code>FilterBypass</code> as
* necessary.
*
* @param fb FilterBypass that can be used to mutate Document
* @param offset the offset from the beginning >= 0
* @param length the number of characters to remove >= 0
* @exception BadLocationException some portion of the removal range
* was not a valid part of the document. The location in the exception
* is the first bad position encountered.
*/
public void remove(FilterBypass fb, int offset, int length) throws
BadLocationException {
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
String newText = text.substring(0, offset) + text.substring(offset + length);
if (newText.matches(regex) || newText.length() == 0) {
super.remove(fb, offset, length);
}
}
/**
* Invoked prior to replacing a region of text in the
* specified Document. Subclasses that want to conditionally allow
* replace should override this and only call supers implementation as
* necessary, or call directly into the FilterBypass.
*
* @param fb FilterBypass that can be used to mutate Document
* @param offset Location in Document
* @param length Length of text to delete
* @param _text Text to insert, null indicates no text to insert
* @param attrs AttributeSet indicating attributes of inserted text,
* null is legal.
* @exception BadLocationException the given insert position is not a
* valid position within the document
*/
public void replace(FilterBypass fb, int offset, int length,
String _text, AttributeSet attrs) throws BadLocationException {
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
String newText = text.substring(0, offset) + _text + text.substring(offset + length);
if (newText.length() <= maxCharacters && newText.matches(regex)) {
super.replace(fb, offset, length, _text, attrs);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
/**
* Invoked prior to insertion of text into the
* specified Document. Subclasses that want to conditionally allow
* insertion should override this and only call supers implementation as
* necessary, or call directly into the FilterBypass.
*
* @param fb FilterBypass that can be used to mutate Document
* @param offset the offset into the document to insert the content >= 0.
* All positions that track change at or after the given location
* will move.
* @param string the string to insert
* @param attr the attributes to associate with the inserted
* content. This may be null if there are no attributes.
* @exception BadLocationException the given insert position is not a
* valid position within the document
*/
public void insertString(FilterBypass fb, int offset, String string,
AttributeSet attr) throws BadLocationException {
String text = fb.getDocument().getText(0, fb.getDocument().getLength());
String newText = text.substring(0, offset) + string + text.substring(offset);
if ((fb.getDocument().getLength() + string.length()) <= maxCharacters
&& newText.matches(regex)) {
super.insertString(fb, offset, string, attr);
} else {
Toolkit.getDefaultToolkit().beep();
}
}
});
return field;
}