Java this.addKeyListener(输入);不起作用,但frame.addKeyListener起作用(仅在短时间内)

Java this.addKeyListener(输入);不起作用,但frame.addKeyListener起作用(仅在短时间内),java,eclipse,Java,Eclipse,我希望能够在我拥有的显示窗口中键入内容,但每当我添加 this.addKeyListener(input); 它什么也不做,但是 frame.addKeyListener(input); 有效,但只是短暂的一段时间。输入一点后,它向我抛出错误: Exception in thread "Thread-1" java.util.ConcurrentModificationException<br> at java.util.AbstractList$Itr.checkForComo

我希望能够在我拥有的显示窗口中键入内容,但每当我添加

this.addKeyListener(input);
它什么也不做,但是

frame.addKeyListener(input);
有效,但只是短暂的一段时间。输入一点后,它向我抛出错误:

Exception in thread "Thread-1" java.util.ConcurrentModificationException<br>
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)<br>
at java.util.AbstractList$Itr.next(Unknown Source)<br>
at net.textBasedGame.Display.getInputAsString(Display.Java:52)<br>
at net.textBasedGame.Display.render(Display.java:81)
at net.textBasedGame.Display.run(Display.java:37)
at java.lang.Thread.run(Unknown Source)
不工作

package net.textBasedGame;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;
import.javax.swing.JFrame;

public class Display extends Canvas implements Runnable {

public static final int GAMEWIDTH = 600;
public static final int GAMEHEIGHT = 600;
private boolean waitingForInput;
public boolean running;
private Input input;
private ArrayList<Character> userInput = new ArrayList<Character>();

public void run() {
init();
running = true;
waitingForInput = true;
while(running){
BufferStrategy bs = getBufferStrategy();
if(bs == null){
createBufferStrategy(2);
continue;
}
Graphics g = bs.getDrawGraphics();
render(g);
bs.show();
}
}

public String getInputAsString(){
String result = "";
for(Character c: userInput){
result += c;
}
return result;

}

public void addCharToArray(Character c){
userInput.add(c);
}

public void setWaitingforInputfalse(){
waitingForInput = false;
}

public boolean isWaitingForInput(){
return waitingForInput
}

public void render(Graphics g){
Graphics 2D g1 = (Graphics2D) g;
g1.setColor(Color.BLACK);
g1.fillRect(0, 0, GAMEWIDTH, GAMEHEIGHT);
g1.setColor(Color.BLUE);
g1.fillRect(100, 100, 50, 50);
g1.setColor(Color.Blue);
g1.fillRect(450, 100, 50, 50);
g1.setFont(new Font("Arial", Font.PLAIN, 30));
g1.setColor(Color.RED);
g1.drawString(getInputAsString(), 10, 300);
}

static public void main(String [] argv){
new Display().start();
}

public void start(){
Thread t = new Thread(this);
t.setPriority(Thread.MAX_PRIORITY);
t.start();
}
public void init(){
input = new Input(this);
JFrame frame = new JFrame("Text Based Game");
frame.setSize(GAMEWIDTH, GAMEHEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
frame.IgnoreRepaint(true);
frame.setLocationRelativeTo(null);
frame.addKeyListener(input);
frame.add(this);
}
}

当您在迭代ArrayList时修改它,并且从一个线程更新列表并从另一个线程进行迭代时,会出现此异常。一个快速修复方法是使所有接触列表的方法同步,这样就没有两个线程可以同时进入它们;即:

public synchronized String getInputAsString(){
    ....
}


public synchronized void addCharToArray(Character c){
    ....
}

您的问题是,一般来说,Swing(JFrame)不是线程安全的。除非另有说明,否则必须在事件调度线程上访问所有Swing组件和相关类

Swing事件处理代码在称为事件的特殊线程上运行 调度线程。大多数调用Swing方法的代码也在上运行 这根线。这是必要的,因为大多数Swing对象方法都是 非“线程安全”:从多个线程调用它们会导致线程风险 干扰或内存一致性错误

“事件分派线程”的概念在这里有更详细的解释:

然而,影响在于构造和显示一个摆动 应用调用应用程序的主方法,或 小程序,则不会在事件调度线程上调用。因此,请小心 必须在以下情况下将控制转移到事件调度线程 构造并显示应用程序或小程序

关于这个主题的更多信息,这里有一个很好的相关答案:

package net.textBasedGame;

import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;

public class Input implements KeyListener {

private Display dis;
private int keyCode;

public Input(Display display){
dis = display;
}

public void keyPressed(KeyEvent e) {

}

public void keyReleased(KeyEvent e) {

}

public void keyTyped(Key event e){
int keyCode = e.getKeyCode();
Character keyLetter = e.getKeyChar();
if(Character.*isLetterOrDigit*(keyLetter) || keyLetter.equals('?') || Character.isSpaceChar(keyLetter)){

}
if(dis.isWaitingForInput()){
dis.addCharToArray(keyLetter);
}

else if(keyCode == KeyEvent.VK_ENTER){
dis.setWaitingforInputfalse();
}
}
}
public synchronized String getInputAsString(){
    ....
}


public synchronized void addCharToArray(Character c){
    ....
}