gpt4 book ai didi

java - JTextField DocumentListener 异常变异错误

转载 作者:行者123 更新时间:2023-12-01 20:26:58 25 4
gpt4 key购买 nike

编辑:您认为可能重复的问题的解决方案( 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 enter image description here

第 2 步:在字符组合框中选择云 enter image description here

第 3 步:输入整数并识别问题 enter image description here enter image description here

我注意到它在尝试访问对象并执行 setValue() method 时发出提示。在线 #1338...有人知道为什么会发生这种情况吗?

更新:

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:我开始使用 SwingUtilities.invokeLater正如 camickr 所建议的那样。它与我在上面的代码片段中注释掉的行一起工作,但是,它将它设置为无限循环......

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();
}
}
}
);
}

我似乎无法正确设置 boolean 标志的组合来阻止它进行无限循环,但仍然执行行 System.out.println("run"); JTextField 中所做的每一个更改。如果我更改 if statement来自if (!newTextReplaceSet || !newTextInsertSet || newTextRemoveSet)if (!newTextReplaceSet || newTextInsertSet || newTextRemoveSet) ,它将从执行 System.out.println("run"); 开始使用无限循环,只执行一次(并且当对 JTextField 进行另一次更改时不会再次执行)。谁能帮我吗?

最佳答案

For some reason, this worked okay when using actionListener

这是因为 ActionListener 代码是在 Document 更新后调用的。

I used the 3 override methods when writing the custom DocumentListener. However, this did not solve the problem

问题是您无法更改 DocumentListener 中的 Document,因为 Document 尚未使用更改的文本进行更新。

真正的问题是,当您在文本字段中输入文本时,为什么要尝试更新文本字段?

如果您确实需要这样做,那么有两种常见的解决方案:

  1. 不要使用 DocumentListener。相反,您可以使用 DocumentFilter,它允许您在添加/删除测试时操作文档。

  2. 您需要延迟更新文档。执行此操作的方法是使用 SwingUtilities.invokeLater(...)。这会将代码放置在事件调度线程 (EDT) 的末尾。

baseHp cannot iterate above 9999).

然后这是基于编辑的逻辑,应该在 DocumentFilter 中完成。或者您甚至可以使用 JFormattedTextField 或 JSpinner。

阅读Swing Tutorial 。有使用 JFormattedTextField 和 JSpinner 的示例。您还可以在“文本组件功能”部分中找到 DocumentFilter 的示例。

编辑:

however, it sets it off into an infinite loop...

首先您需要了解使用 DocumentListener 和 DocumentFilter 之间的区别。

  1. DocumentListener 用于在文档中添加/删除数据后在应用程序中进行处理

  2. DocumentFilter 用于在将数据添加到文档之前编辑数据

但是,这两种情况下的循环问题是相同的,解决方案也是相同的。

问题是你:

  1. 在文本字段中输入文本
  2. 调用监听器
  3. 您操作文本并使用 setText() 重置数据
  4. 再次调用监听器。
  5. ... 3 和 4 不断重复。

因此,解决方案是在调用 setText(...) 方法之前删除 Listener,然后恢复 Listener。

doc.removeDocumentListener( this );
textfield.setText(...);
doc.addDocumentListener( this );

虽然我想说实际更改输入的数据是不正常的。通常,您会验证数据并在出现错误时显示一条消息,而不是尝试修复数据并重置文本。通过不更改文本字段,您不必担心导致无限循环。

这就是为什么您会使用 JFormattedTextField 或 JSpinner 作为编辑组件。您可以轻松地将数据强制为具有最大位数的数字。

关于java - JTextField DocumentListener 异常变异错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43738710/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com