AWT-EventQueue-0 java.lang.ArrayIndexOutOfBoundsException:{value}(程序仍在运行)

时间:2017-11-20 17:10:42

标签: java

所以我在发布之前看了这个错误,并且理解它与尝试引用数组范围之外的数组值有关,但令我困惑的是我的类仍在运行好像错误从未发生过(我猜这是不同的线程),并且我的代码中没有任何东西似乎导致错误(我一直跟着堆栈跟踪);看到错误每隔一段时间弹出就很烦人了,我想知道如何修复它。

我的类是一个基于文本的网格显示,允许键盘输入(我不扩展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的帮助。

1 个答案:

答案 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);
}