所以我在发布之前看了这个错误,并且理解它与尝试引用数组范围之外的数组值有关,但令我困惑的是我的类仍在运行好像错误从未发生过(我猜这是不同的线程),并且我的代码中没有任何东西似乎导致错误(我一直跟着堆栈跟踪);看到错误每隔一段时间弹出就很烦人了,我想知道如何修复它。
我的类是一个基于文本的网格显示,允许键盘输入(我不扩展JFrame类,因为我不希望任何人能够调整显示大小,而不是通过更改“宽度”和“高度” “田野”。我用一个主方法将它连接到另一个类,该方法使用显示器来播放基于文本的顶级平台游戏,以使错误更加明显。当我四处走动时,我经常会遇到与此类似的错误:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
at javax.swing.text.CompositeView.getView(CompositeView.java:160)
at javax.swing.text.Utilities.getNextVisualPositionFrom(Utilities.java:1030)
at javax.swing.text.CompositeView.getNextEastWestVisualPositionFrom(CompositeView.java:757)
at javax.swing.text.CompositeView.getNextVisualPositionFrom(CompositeView.java:479)
at javax.swing.plaf.basic.BasicTextUI$RootView.getNextVisualPositionFrom(BasicTextUI.java:1588)
at javax.swing.plaf.basic.BasicTextUI.getNextVisualPositionFrom(BasicTextUI.java:1127)
at javax.swing.text.DefaultEditorKit$NextVisualPositionAction.actionPerformed(DefaultEditorKit.java:1690)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1663)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2882)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2929)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2845)
at java.awt.Component.processEvent(Component.java:6310)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1954)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:806)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1074)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:945)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:771)
at java.awt.Component.dispatchEventImpl(Component.java:4760)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
这是我的班级:
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
public class TextDisplay {
private int width;
private int height;
private int fontSize;
private double fontSpacing;
private char lastChar = 0;
private int lastKeyPress = 0;
private int lastKeyRelease = 0;
private JFrame mainframe;
private JTextPane field;
public TextDisplay(int width, int height) {
this.width = width;
this.height = height;
createGUI(false);
clearDisplay();
}
public TextDisplay(int width, int height, boolean visibility) {
this.width = width;
this.height = height;
createGUI(visibility);
clearDisplay();
}
private void createGUI(boolean visibility) {
mainframe = new JFrame();
if ((this.width < 1) || (this.height < 1)) {
throw new IllegalArgumentException();
}
mainframe.setResizable(false);
mainframe.setDefaultCloseOperation(3);
field = new JTextPane();
field.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
lastChar = e.getKeyChar();
}
public void keyPressed(KeyEvent e) {
lastKeyPress = e.getKeyCode();
}
public void keyReleased(KeyEvent e) {
lastKeyRelease = e.getKeyCode();
}
});
field.setEditable(false);
setFont(70, 0.0);
clearDisplay();
mainframe.add(field);
if (visibility) {
mainframe.setVisible(true);
}
}
public int getLastKeyPress() {
return lastKeyPress;
}
public int getLastKeyRelease() {
return lastKeyRelease;
}
public char getLastKeyTyped() {
return lastChar;
}
public void clearLastKeyPress() {
lastKeyPress = 0;
}
public void clearLastKeyRelease() {
lastKeyRelease = 0;
}
public void clearLastKeyTyped() {
lastChar = 0;
}
private int calcWindowWidth() {
FontMetrics fm = field.getFontMetrics(new Font("Consolas", 0, this.fontSize));
return 12 + fm.charWidth(' ') * this.width;
}
private int calcWindowHeight() {
FontMetrics fm = field.getFontMetrics(new Font("Consolas", 0, this.fontSize));
double s = this.fontSpacing;
int fh = fm.getHeight();
int h = this.height;
double tf = Math.signum(s) * -4;
int pixels = 40 + fh * h;
double spacingPixels = roundB(fh * s * (h - 1));
int oddPixels = (int) roundB(tf * Math.floor(8 * s / tf) - 8 * s);
int extraPixels = (int) spacingPixels;
return pixels + extraPixels - oddPixels;
}
public static double roundB(double value) {
return Math.round(value * 100000000000.0) / 100000000000.0;
}
public void refresh() {
mainframe.setVisible(false);
mainframe.setVisible(true);
}
public void dispose() {
mainframe.dispose();
}
public boolean isDisplayable() {
return mainframe.isDisplayable();
}
public void setVisible(boolean visibility) {
mainframe.setVisible(visibility);
}
public void setTitle(String name) {
mainframe.setTitle(name);
}
public int getFontSize() {
return this.fontSize;
}
public double getFontSpacing() {
return this.fontSpacing;
}
public void setFontSize(int fontSize) {
setFont(fontSize, this.fontSpacing);
}
public void setFontSpacing(double fontSpacing) {
setFont(this.fontSize, fontSpacing);
}
public void setFont(int fontSize, double fontSpacing) {
this.fontSize = fontSize;
this.fontSpacing = roundB(fontSpacing);
mainframe.setSize(calcWindowWidth(), calcWindowHeight());
StyledDocument doc = field.getStyledDocument();
MutableAttributeSet mas = new SimpleAttributeSet();
StyleConstants.setLineSpacing(mas, (float) this.fontSpacing);
StyleConstants.setFontSize(mas, this.fontSize);
StyleConstants.setFontFamily(mas, "Consolas");
doc.setParagraphAttributes(0, 1000, mas, true);
field.setStyledDocument(doc);
}
public void setDefaultCloseOperation(int operation) {
mainframe.setDefaultCloseOperation(operation);
}
public void clearDisplay() {
StringBuilder display = new StringBuilder();
for (int row = 0; row < this.height; row++) {
for (int col = 0; col < this.width; col++) {
display.append(' ');
}
display.append('\n');
}
field.setText(display.toString());
}
public void setDisplay(char[][] charMap) {
StringBuilder display = new StringBuilder();
if (charMap.length != this.height) {
throw new IllegalArgumentException("rows = " + charMap.length + ", this.height = " + this.height);
}
for (int row = 0; row < charMap.length; row++) {
if (charMap[row].length != this.width) {
throw new IllegalArgumentException(
"row = " + row + ", length = " + charMap[row].length + ", this.width = " + this.width);
}
char[] arrayOfChar;
int j = (arrayOfChar = charMap[row]).length;
for (int i = 0; i < j; i++) {
char c = arrayOfChar[i];
display.append(c);
}
display.append('\n');
}
field.setText(display.toString());
}
public void setDisplay(String[] lines) {
StringBuilder display = new StringBuilder();
if (lines.length != this.height) {
throw new IllegalArgumentException("rows = " + lines.length + ", this.height = " + this.height);
}
for (int i = 0; i < lines.length; i++) {
String string = lines[i];
if (string.length() != this.width) {
throw new IllegalArgumentException(
"row = " + i + ", length = " + string.length() + ", this.width = " + this.width);
}
display.append(string + '\n');
}
field.setText(display.toString());
}
public String[] getDisplay() {
return field.getText().split("\n");
}
public char[][] getDisplayCharMap() {
String[] display = getDisplay();
char[][] charMap = new char[this.height][this.width];
for (int row = 0; row < this.height; row++) {
charMap[row] = display[row].toCharArray();
}
return charMap;
}
public void setCharAt(char character, int row, int col) {
char[][] display = getDisplayCharMap();
if ((row >= this.height) || (col >= this.width) || (row < 0) || (col < 0)) {
throw new IllegalArgumentException("row = " + row + ", this.height = " + this.height + ", col = " + col
+ ", this.width = " + this.width);
}
display[row][col] = character;
setDisplay(display);
}
public char getCharAt(int row, int col) {
char[][] display = getDisplayCharMap();
if ((row >= this.height) || (col >= this.width) || (row < 0) || (col < 0)) {
throw new IllegalArgumentException("row = " + row + ", col = " + col);
}
return display[row][col];
}
public void output(String text, int row, int col) {
char[][] display = getDisplayCharMap();
if ((row >= this.height) || (col >= this.width) || (row < 0) || (col < 0)) {
throw new IllegalArgumentException("row = " + row + ", col = " + col);
}
char[] arrayOfChar = text.toCharArray();
for (char c : arrayOfChar) {
display[row][col] = c;
col++;
if (col >= this.width) {
col = 0;
row++;
}
if (row >= this.height) {
row = 0;
}
}
setDisplay(display);
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
}
这是我使用main方法的类:
import java.awt.event.KeyEvent;
public class Main {
volatile static int key;
public static void main(String[] args) {
TextDisplay display = new TextDisplay(10, 5);
display.setDisplay(new String[] {"OXXXXXXXXO","X X","X X","X X","OXXXXXXXXO"});
display.setVisible(true);
int x = 1;
int y = 1;
boolean gameRunning = true;
display.setCharAt('P', y, x);
while (gameRunning) {
key = display.getLastKeyPress();
if (key != 0) {
display.setCharAt(' ', y, x);
switch (key) {
case KeyEvent.VK_LEFT:
if (display.getCharAt(y, x - 1) == ' ') x--;
break;
case KeyEvent.VK_UP:
if (display.getCharAt(y - 1, x) == ' ') y--;
break;
case KeyEvent.VK_RIGHT:
if (display.getCharAt(y, x + 1) == ' ') x++;
break;
case KeyEvent.VK_DOWN:
if (display.getCharAt(y + 1, x) == ' ') y++;
break;
}
display.setCharAt('P', y, x);
display.clearLastKeyPress();
}
}
}
}
我可以忍受错误,但它很烦人;有人可以帮我解决这个问题吗?
编辑:认为这是不切实际的,所以我只是扩展了JFrame,并在我用invokeLater
更改显示时随时换行。当我这样做时,错误消失了。感谢tsolakp的帮助。
答案 0 :(得分:0)
您正在从while
循环内的主线程更改Swing UI状态。
请记住,在setVisible
对象上调用display
后,会启动事件调度线程,并且您无法在该调用后直接修改UI。
Swing不保证在此类用途中正常运行。
尝试将所有调用包装到display' variable after
setVisible call with
invokeLater`。
1)以下是使用invokeLater
的代码:
public static void main(String[] args) {
TextDisplay display = new TextDisplay(10, 5);
display.setDisplay(new String[] {"OXXXXXXXXO","X X","X X","X X","OXXXXXXXXO"});
display.setVisible(true);
Helper helper = new Helper(display);
boolean gameRunning = true;
while (gameRunning) {
SwingUtilities.invokeLater( () -> helper.check() );
}
}
private static class Helper{
int x = 1;
int y = 1;
TextDisplay display = null;
public Helper(TextDisplay display){
this.display = display;
display.setCharAt('P', y, x);
}
public void check(){
int key = display.getLastKeyPress();
if (key != 0) {
display.setCharAt(' ', y, x);
switch (key) {
case KeyEvent.VK_LEFT:
if (display.getCharAt(y, x - 1) == ' ') x--;
break;
case KeyEvent.VK_UP:
if (display.getCharAt(y - 1, x) == ' ') y--;
break;
case KeyEvent.VK_RIGHT:
if (display.getCharAt(y, x + 1) == ' ') x++;
break;
case KeyEvent.VK_DOWN:
if (display.getCharAt(y + 1, x) == ' ') y++;
break;
}
display.setCharAt('P', y, x);
display.clearLastKeyPress();
}
}
}
2)你根本不需要while
循环。只需听取关键事件。我只是通过invokeLater
宣传方法,以便您熟悉如何使用它:
public static void main(String[] args) {
TextDisplay display = new TextDisplay(10, 5);
Helper helper = new Helper(display);
display.setDisplay(new String[] {"OXXXXXXXXO","X X","X X","X X","OXXXXXXXXO"});
display.addKeyListener(helper);
display.setVisible(true);
}
private static class Helper extends KeyAdapter{
int x = 1;
int y = 1;
TextDisplay display = null;
public Helper(TextDisplay display){
this.display = display;
display.setCharAt('P', y, x);
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key != 0) {
display.setCharAt(' ', y, x);
switch (key) {
case KeyEvent.VK_LEFT:
if (display.getCharAt(y, x - 1) == ' ') x--;
break;
case KeyEvent.VK_UP:
if (display.getCharAt(y - 1, x) == ' ') y--;
break;
case KeyEvent.VK_RIGHT:
if (display.getCharAt(y, x + 1) == ' ') x++;
break;
case KeyEvent.VK_DOWN:
if (display.getCharAt(y + 1, x) == ' ') y++;
break;
}
display.setCharAt('P', y, x);
}
}
}
并将此方法添加到TextDisplay:
public void addKeyListener(KeyListener kl){
field.addKeyListener(kl);
}