带有 invokelater 的 documentlistener 进入无限循环
documentlistener with invokelater goes infinite loop
我有一个带有文本字段的 Jpanel。我正在使用 documentListener 将更改保存为用户在文本字段中键入的内容。用户可以在 1-1000 之间输入,如果他输入任何其他内容,将会弹出错误消息。
现在,我正在使用 invokeLater,但如果用户输入 >1000,则会导致无限循环。我该如何解决这个问题。
mMaxLabelLength = new JTextField();
mMaxLabelLength.getDocument().addDocumentListener(this);
@Override
public void changedUpdate(DocumentEvent arg0)
{
}
@Override
public void insertUpdate(DocumentEvent arg0)
{
saveActions();
mMaxLabelLength.requestFocus();
}
@Override
public void removeUpdate(DocumentEvent arg0)
{
saveActions();
mMaxLabelLength.requestFocus();
}
private boolean saveActions()
{
// get text
String strValue = mMaxLabelLength.getText();
// validate: must be positive integer between 1-1000;
boolean bSaveIt = true;
try
{
int nValue = Integer.parseInt(strValue);
if (nValue < 1 || nValue > 1000)
bSaveIt = false;
}
catch (NumberFormatException ne)
{
bSaveIt = false;
}
// save data to properties if valid
if (bSaveIt)
{
//do something
}
else
{
// error message
JOptionPane.showMessageDialog(this, "Please enter an integer value between 1 and 1000.", "Invalid Entry", JOptionPane.INFORMATION_MESSAGE);
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
int nMaxLabel = getMaxPieLabel();
mMaxLabelLength.setText(new Integer(nMaxLabel).toString());
}
});
return false;
}
setVisible(true);
return true;
}
修改 Document
的状态或与 UI 交互并不是 DocumentListener
的真正职责范围。
相反,您可能应该使用 DocumentFilter
,这将允许您在无效状态提交到 Document
之前捕获无效状态,并使用自定义事件通知来提醒相关方违规行为已经发生,例如...
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class Example {
public static void main(String[] args) {
new Example();
}
public Example() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(20, 20, 20, 20));
JTextField field = new JTextField(10);
LimitedRangeDocumentFilter filter = new LimitedRangeDocumentFilter(1, 1000);
filter.setLimitedRangeDocumentFilterListener(new LimitedRangeDocumentFilterListener() {
@Override
public void updateWouldBeInvalid(LimitedRangeDocumentFilter filter, String text) {
JOptionPane.showMessageDialog(TestPane.this,
text + " is not within " + filter.getMin() + "-" + filter.getMax() + " range",
"Error",
JOptionPane.ERROR_MESSAGE);
}
});
((AbstractDocument)field.getDocument()).setDocumentFilter(filter);
add(field);
}
}
public interface LimitedRangeDocumentFilterListener {
public void updateWouldBeInvalid(LimitedRangeDocumentFilter filter, String text);
}
public class LimitedRangeDocumentFilter extends DocumentFilter {
private int min;
private int max;
private LimitedRangeDocumentFilterListener listener;
public LimitedRangeDocumentFilter(int min, int max) {
this.min = min;
this.max = max;
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
public void setLimitedRangeDocumentFilterListener(LimitedRangeDocumentFilterListener listener) {
this.listener = listener;
}
@Override
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String string, AttributeSet attr)
throws BadLocationException {
StringBuilder sb = new StringBuilder(string);
for (int i = sb.length() - 1; i >= 0; i--) {
char ch = sb.charAt(i);
if (!Character.isDigit(ch)) {
sb.deleteCharAt(i);
}
}
StringBuilder master = new StringBuilder(fb.getDocument().getText(0, fb.getDocument().getLength()));
master.insert(offset, sb.toString());
if (wouldBeValid(master.toString())) {
super.insertString(fb, offset, sb.toString(), attr);
} else if (listener != null) {
listener.updateWouldBeInvalid(this, master.toString());
}
}
@Override
public void replace(DocumentFilter.FilterBypass fb,
int offset, int length, String string, AttributeSet attr) throws BadLocationException {
if (length > 0) {
fb.remove(offset, length);
}
insertString(fb, offset, string, attr);
}
protected boolean wouldBeValid(String text) {
boolean wouldBeValid = false;
try {
int value = Integer.parseInt(text);
if (value >= min && value <= max) {
wouldBeValid = true;
}
} catch (NumberFormatException exp) {
}
return wouldBeValid;
}
}
}
有关详细信息,请参阅 Implementing a Document Filter and DocumentFilter Examples
我有一个带有文本字段的 Jpanel。我正在使用 documentListener 将更改保存为用户在文本字段中键入的内容。用户可以在 1-1000 之间输入,如果他输入任何其他内容,将会弹出错误消息。 现在,我正在使用 invokeLater,但如果用户输入 >1000,则会导致无限循环。我该如何解决这个问题。
mMaxLabelLength = new JTextField();
mMaxLabelLength.getDocument().addDocumentListener(this);
@Override
public void changedUpdate(DocumentEvent arg0)
{
}
@Override
public void insertUpdate(DocumentEvent arg0)
{
saveActions();
mMaxLabelLength.requestFocus();
}
@Override
public void removeUpdate(DocumentEvent arg0)
{
saveActions();
mMaxLabelLength.requestFocus();
}
private boolean saveActions()
{
// get text
String strValue = mMaxLabelLength.getText();
// validate: must be positive integer between 1-1000;
boolean bSaveIt = true;
try
{
int nValue = Integer.parseInt(strValue);
if (nValue < 1 || nValue > 1000)
bSaveIt = false;
}
catch (NumberFormatException ne)
{
bSaveIt = false;
}
// save data to properties if valid
if (bSaveIt)
{
//do something
}
else
{
// error message
JOptionPane.showMessageDialog(this, "Please enter an integer value between 1 and 1000.", "Invalid Entry", JOptionPane.INFORMATION_MESSAGE);
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
int nMaxLabel = getMaxPieLabel();
mMaxLabelLength.setText(new Integer(nMaxLabel).toString());
}
});
return false;
}
setVisible(true);
return true;
}
修改 Document
的状态或与 UI 交互并不是 DocumentListener
的真正职责范围。
相反,您可能应该使用 DocumentFilter
,这将允许您在无效状态提交到 Document
之前捕获无效状态,并使用自定义事件通知来提醒相关方违规行为已经发生,例如...
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class Example {
public static void main(String[] args) {
new Example();
}
public Example() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(20, 20, 20, 20));
JTextField field = new JTextField(10);
LimitedRangeDocumentFilter filter = new LimitedRangeDocumentFilter(1, 1000);
filter.setLimitedRangeDocumentFilterListener(new LimitedRangeDocumentFilterListener() {
@Override
public void updateWouldBeInvalid(LimitedRangeDocumentFilter filter, String text) {
JOptionPane.showMessageDialog(TestPane.this,
text + " is not within " + filter.getMin() + "-" + filter.getMax() + " range",
"Error",
JOptionPane.ERROR_MESSAGE);
}
});
((AbstractDocument)field.getDocument()).setDocumentFilter(filter);
add(field);
}
}
public interface LimitedRangeDocumentFilterListener {
public void updateWouldBeInvalid(LimitedRangeDocumentFilter filter, String text);
}
public class LimitedRangeDocumentFilter extends DocumentFilter {
private int min;
private int max;
private LimitedRangeDocumentFilterListener listener;
public LimitedRangeDocumentFilter(int min, int max) {
this.min = min;
this.max = max;
}
public int getMin() {
return min;
}
public int getMax() {
return max;
}
public void setLimitedRangeDocumentFilterListener(LimitedRangeDocumentFilterListener listener) {
this.listener = listener;
}
@Override
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String string, AttributeSet attr)
throws BadLocationException {
StringBuilder sb = new StringBuilder(string);
for (int i = sb.length() - 1; i >= 0; i--) {
char ch = sb.charAt(i);
if (!Character.isDigit(ch)) {
sb.deleteCharAt(i);
}
}
StringBuilder master = new StringBuilder(fb.getDocument().getText(0, fb.getDocument().getLength()));
master.insert(offset, sb.toString());
if (wouldBeValid(master.toString())) {
super.insertString(fb, offset, sb.toString(), attr);
} else if (listener != null) {
listener.updateWouldBeInvalid(this, master.toString());
}
}
@Override
public void replace(DocumentFilter.FilterBypass fb,
int offset, int length, String string, AttributeSet attr) throws BadLocationException {
if (length > 0) {
fb.remove(offset, length);
}
insertString(fb, offset, string, attr);
}
protected boolean wouldBeValid(String text) {
boolean wouldBeValid = false;
try {
int value = Integer.parseInt(text);
if (value >= min && value <= max) {
wouldBeValid = true;
}
} catch (NumberFormatException exp) {
}
return wouldBeValid;
}
}
}
有关详细信息,请参阅 Implementing a Document Filter and DocumentFilter Examples