编辑:您认为可能重复的问题的解决方案(java.lang.IllegalStateException while using Document Listener in TextArea, Java)正是我在代码中输入的解决此问题的方法。在编写自定义DocumentListener时,我使用了3种覆盖方法。但是,这并不能解决问题。
由于某些原因,使用actionListener
时此方法可以正常工作(请参阅此处-Update JTextField.addActionListener without pressing "enter")。 actionListener
的问题是,每次我想更新标签时,我都必须打“ enter”。因此有人建议使用DocumentListener
代替。完成此操作。我遇到了我无法弄清的错误,以及非常奇怪的行为。
由于代码太大而无法在此处发布,因此我将项目压缩(与Intellij和JRE 1.8结合使用)> https://www.dropbox.com/s/pf4hiuk9y0jby7y/FF7LevelUpStatCalculator.zip?dl=0
隔离发生问题的代码块(以便快速查看):
private void setHpBaseStatsTextFieldAction(){
hpBaseStatsTextField.getDocument().addDocumentListener(
new DocumentListener() {
public void insertUpdate(DocumentEvent e) {
updateStatGridLabels();
}
public void removeUpdate(DocumentEvent e) {
updateStatGridLabels();
}
public void changedUpdate(DocumentEvent e) {
//Plain text components do not fire these events
}
public void updateStatGridLabels() {
String currCharacter = charSelCombo.getSelectedItem().toString();
String checkBaseHpInGui = hpBaseStatsTextField.getText();
int baseHpInGui = 0;
if (isInteger(checkBaseHpInGui)){
baseHpInGui = Integer.parseInt(checkBaseHpInGui);
}
if ((!(currCharacter.equals(guiCharSelDefaultValue[unselectedDefaultElement]))) && (isInteger(checkBaseHpInGui))){
characters[getSelectedCharactersIndex()].setBaseHp(baseHpInGui);
hpBaseStatsTextField.setText(Integer.toString(characters[getSelectedCharactersIndex()].getBaseHp()));
setHpStatGridRowValues();
}
}
}
);
}
重现问题:
步骤1:运行StartGui.java
步骤2:在角色组合框中选择Cloud
步骤3:输入整数并识别问题
我注意到它在尝试访问对象并在#1338行上执行
setValue() method
时在抱怨...任何人都知道为什么会发生这种情况?更新:
只要我注释掉一行(检查最大值的规则时就需要),DocumentFilter似乎就可以正确地执行此操作。这是到目前为止的代码:
private void setHpBaseStatsTextFieldAction(){
((AbstractDocument) hpBaseStatsTextField.getDocument()).setDocumentFilter(
new DocumentFilter() {
public void replace(DocumentFilter.FilterBypass fb, int offset, int length,
String text, AttributeSet attrs) throws BadLocationException {
if (offset >= fb.getDocument().getLength()) {
System.out.println("Added: " + text);
} else {
String old = fb.getDocument().getText(offset, length);
System.out.println("Replaced " + old + " with " + text);
}
super.replace(fb, offset, length, text, attrs);
updateStatGridLabels();
}
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String text, AttributeSet attr) throws BadLocationException {
System.out.println("Added: " + text);
super.insertString(fb, offset, text, attr);
updateStatGridLabels();
}
public void remove(DocumentFilter.FilterBypass fb, int offset, int length)
throws BadLocationException {
System.out.println("Removed: " + fb.getDocument().getText(offset, length));
super.remove(fb, offset, length);
updateStatGridLabels();
}
public void updateStatGridLabels() {
String currCharacter = charSelCombo.getSelectedItem().toString();
String checkBaseHpInGui = hpBaseStatsTextField.getText();
int baseHpInGui = 0;
if (isInteger(checkBaseHpInGui)){
baseHpInGui = Integer.parseInt(checkBaseHpInGui);
}
if ((!(currCharacter.equals(guiCharSelDefaultValue[unselectedDefaultElement]))) && (isInteger(checkBaseHpInGui))){
characters[getSelectedCharactersIndex()].setBaseHp(baseHpInGui);
//hpBaseStatsTextField.setText(Integer.toString(characters[getSelectedCharactersIndex()].getBaseHp()));
setHpStatGridRowValues();
}
}
}
);
}
我仍然可以使用一些帮助。
更新2:我开始按照camickr的建议使用
SwingUtilities.invokeLater
。它可以与我在上面的代码段中注释掉的行一起使用,但是,它会将它设置为无限循环...private void setHpBaseStatsTextFieldAction(){
((AbstractDocument) hpBaseStatsTextField.getDocument()).setDocumentFilter(
new DocumentFilter() {
boolean newTextReplaceSet = false;
public void replace(DocumentFilter.FilterBypass fb, int offset, int length,
String text, AttributeSet attrs) throws BadLocationException {
if (offset >= fb.getDocument().getLength()) {
System.out.println("Added: " + text);
} else {
String old = fb.getDocument().getText(offset, length);
System.out.println("Replaced " + old + " with " + text);
}
super.replace(fb, offset, length, text, attrs);
updateStatGridLabels();
newTextReplaceSet = true;
}
boolean newTextInsertSet = false;
public void insertString(DocumentFilter.FilterBypass fb, int offset,
String text, AttributeSet attr) throws BadLocationException {
System.out.println("Added: " + text);
super.insertString(fb, offset, text, attr);
updateStatGridLabels();
newTextInsertSet = true;
}
boolean newTextRemoveSet = false;
public void remove(DocumentFilter.FilterBypass fb, int offset, int length)
throws BadLocationException {
System.out.println("Removed: " + fb.getDocument().getText(offset, length));
super.remove(fb, offset, length);
updateStatGridLabels();
newTextRemoveSet = true;
}
public void updateStatGridLabels() {
String currCharacter = charSelCombo.getSelectedItem().toString();
String checkBaseHpInGui = hpBaseStatsTextField.getText();
int baseHpInGui = 0;
if (isInteger(checkBaseHpInGui)){
baseHpInGui = Integer.parseInt(checkBaseHpInGui);
}
if ((!(currCharacter.equals(guiCharSelDefaultValue[unselectedDefaultElement]))) && (isInteger(checkBaseHpInGui))){
characters[getSelectedCharactersIndex()].setBaseHp(baseHpInGui);
if (!newTextReplaceSet || !newTextInsertSet || newTextRemoveSet) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println("run");
hpBaseStatsTextField.setText(Integer.toString(characters[getSelectedCharactersIndex()].getBaseHp()));
}
});
}
//hpBaseStatsTextField.setText(Integer.toString(characters[getSelectedCharactersIndex()].getBaseHp()));
setHpStatGridRowValues();
}
}
}
);
}
我似乎无法正确设置布尔标志的组合以阻止它进行无限循环,但仍然对JTextField中进行的每个更改执行
System.out.println("run");
行。如果将if statement
从if (!newTextReplaceSet || !newTextInsertSet || newTextRemoveSet)
更改为if (!newTextReplaceSet || newTextInsertSet || newTextRemoveSet)
,它将从执行无限循环的System.out.println("run");
变为仅执行一次(而对JTextField
进行另一次更改则不再执行)。谁能帮我? 最佳答案
出于某种原因,使用actionListener时可以正常工作
这是因为Document
更新后,将调用ActionListener代码。
在编写自定义DocumentListener时,我使用了3种覆盖方法。但是,这并没有解决问题
问题在于您无法在DocumentListener中更改Document
,因为Document
尚未使用更改后的文本进行更新。
真正的问题是,当您在文本字段中键入文本时,为什么要尝试更新文本字段?
如果您确实需要执行此操作,则有两种常见的解决方案:
不要使用DocumentListener。相反,您可以使用DocumentFilter
,它允许您在添加/删除测试时操作文档。
您需要延迟更新文档。执行此操作的方法是使用SwingUtilities.invokeLater(...)
。这会将代码放在Event Dispatch Thread (EDT)
的末尾。
baseHp无法在9999以上进行迭代。
然后,这是基于编辑的逻辑,应在DocumentFilter中完成。或者甚至可以使用JFormattedTextField或JSpinner。
阅读Swing Tutorial。有使用JFormattedTextField和JSpinner的示例。您还可以在“文本组件功能”部分中找到DocumentFilter的示例。
编辑:
但是,它使它陷入无限循环...
好吧,首先,您需要了解使用DocumentListener和DocumentFilter之间的区别。
从文档中添加/删除数据后,DocumentListener用于在应用程序中进行处理
在将数据添加到文档之前,使用DocumentFilter来编辑数据
但是,在两种情况下循环问题都是相同的,解决方案是相同的。
问题是您:
在文本字段中输入文本
侦听器被调用
您操纵文本并使用setText()重置数据
监听器再次被调用。
... 3和4不断重复。
因此,一种解决方案是在调用setText(...)方法之前删除侦听器,然后还原侦听器。
doc.removeDocumentListener( this );
textfield.setText(...);
doc.addDocumentListener( this );
尽管我会说实际上更改输入的数据是不正常的。通常,您会验证数据并在出现错误时显示一条消息,而不是尝试修复数据并重置文本。通过不更改文本字段,您不必担心引起无限循环。
这就是为什么要使用JFormattedTextField或JSpinner作为编辑组件的原因。您可以轻松地将数据强制为最大位数的数字。