java中的KeyAdapter输入无法正常工作

时间:2017-01-01 18:41:34

标签: java swing keyboard keylistener

我刚刚写了一些代码让我的玩家在我的小迷宫游戏中移动,但没有任何反应。我的迷宫也没有像矩阵输入那样被绘制得正确。我不明白为什么这个代码错了...任何帮助都很好。 谢谢!

INSERT INTO Results (eventID,Result1,Result2,Result3,Result4,Result5)
SELECT eventID, [1] as Result1, [2] as Result2, [3] as Result3, [4] as Result4, [5] as Result5
FROM
(SELECT [inputTable].eventID,[inputTable].eQualType,[inputTable].Value1
FROM eventQData
WHERE eQualType IN (1, 2, 3, 4, 5) AND (Value2 > 0)
) AS inputTable
PIVOT
(MAX(Value1)
FOR [eQualType] IN ([1],[2],[3],[4],[5])

应该看起来像:

enter image description here

1 个答案:

答案 0 :(得分:-1)

问题/建议:

  • 您以默认方式向JFrame添加了多个组件。由于JFrame的contentPane使用BorderLayout,因此只显示一个组件,添加最后一个组件,另一个组件将完全覆盖并保持不可见。
  • 您的主要JPanel未被用作真正的JPanel。没有任何东西被添加到它,事实上它看起来应该是一个逻辑类而不是组件类。
  • 使用Key Bindings而不是使用在焦点问题上非常烦躁的KeyListeners,这样可以让您以干净,更高层次的方式解决焦点问题。
  • 不要覆盖JPanel的paint方法,而是覆盖它的paintComponent方法,因为这会给你带来几个好处,包括默认使用动画的双缓冲。
  • 不要小心地为组件类提供public int getX()public int getY()方法,因为这些方法会覆盖将组件放在其容器中的关键方法。由于Main类甚至不应该扩展JPanel,因此对于您的代码来说这最终会成为一个问题,但将来它会破坏您的程序。
  • 当您遇到类似问题(例如KeyListener无法正常工作)时,请从大型程序中删除该问题,并尝试在一个单独的小程序中重现该问题。这将为您提供更清洁的环境,帮助您隔离和理解您的问题,从而帮助您解决问题。
  • 您的程序误用了static修饰符。您的x和y字段不应该是静态的,不应以静态方式访问。
  • 你的main方法中有太多代码,这是你可能使x和y静态的原因之一,因为你试图在main中访问它们时被迫这样做。解决方案不是让字段保持静态,而是将所有代码从静态世界带入实例世界。

修改

出于某种原因,这个问题引起了我的兴趣,所以我决定尽可能尝试使用M-V-C或模型 - 视图 - 控制器,看看我能想出什么。所以这里有一堆类的工作,从保存数据的文本文件开始。

GUI看起来像:

enter image description here

它必须与类文件位于同一位置,因为它是作为资源获取的,并且必须具有文件名"input.txt"

1111111111111111111111111111111111111111111
1000000010001000001000000010000000100000001
1010111010101010101111101011111010111111101
1010001010100010100000001010000010000010001
1011101010111110101111111010111111111010111
1000101010100000101000001000100010000010001
1011101011101011111011101111111010111110101
1010001000001010000010100000001010000010101
1010111111111010111110111111101011111011101
1010100000100010100000000000101000000000101
1110101111101110111110111011101011111110101
1000100000000010000010100010001000100010001
1011111111111111111011101010111111101011101
1000000000000000100010001010000000001010001
1011111111111011101110111011111111111010111
1000100010001000001010001000100000001010101
1110101011101111111010101110111110111010101
1000101010001000100000101000100000100010001
1011101010111010101111101011101110101111111
1000001010000010000000101000001000100010001
1111111011111110111111101111111011111010101
1000001010000010100010001000000010000010101
1011111010111011101010111011111110101110101
1010000010001010001010001000100000101010101
1010111111101010111011101111101111101011101
1000100000001010101010001000100010101000101
1011111011111010101010111010111010101011101
1010000010001000101010000010001010001000001
1010101110101111101011101111101011111010101
1010101000101000001000101000001000000010101
1011101011111010111110111011101111111110111
1000001000000010000000000010000000000010021
1111111111111111111111111111111111111111111

接下来,主程序,创建模型,视图和控制器的程序,将它们挂钩在一起,然后显示GUI:

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 * link: http://stackoverflow.com/a/41418250/522444
 * 
 * @author Pete
 *
 */
@SuppressWarnings("serial")
public class Main2 extends JPanel {
    private View mainPanel;

    public Main2(MatrixModel matrixModel) {
        mainPanel = new View(matrixModel);
        new Controller(matrixModel, mainPanel);

        setLayout(new BorderLayout());
        add(mainPanel, BorderLayout.CENTER);
    }

    private static void createAndShowGui(MatrixModel model) {
        Main2 mainPanel = new Main2(model);

        JFrame frame = new JFrame("Main2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        final MatrixModel model = MatrixUtil.getInput(MatrixUtil.PATH_TO_RSC);

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui(model);
            }
        });
    }
}

接下来是一个带有静态方法的实用程序类,用于将文本文件作为资源读取并将其转换为Model对象:

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class MatrixUtil {
    // again this text file must be in the jar file or the code base 
    // at the same location as the class / java files
    public static final String PATH_TO_RSC = "input.txt";

    public static MatrixModel getInput(String resourcePath) {
        InputStream is = MatrixUtil.class.getResourceAsStream(resourcePath);
        if (is == null) {
            String text = "resourcePath is not found and not loading text: " + resourcePath;
            throw new IllegalArgumentException(text);
        }
        return getInput(is);
    }

    public static MatrixModel getInput(InputStream is) {
        MatrixModel model = null;
        try (Scanner scan = new Scanner(is)) {
            List<List<MatrixPosition>> listOfLists = new ArrayList<>();
            while (scan.hasNextLine()) {
                String line = scan.nextLine();
                if (line.trim().isEmpty()) {
                    continue;
                }
                List<MatrixPosition> list = new ArrayList<>();
                for (char c : line.toCharArray()) {
                    list.add(MatrixPosition.getMatrixPosition(String.valueOf(c)));
                }
                listOfLists.add(list);
            }
            MatrixPosition[][] grid = new MatrixPosition[listOfLists.size()][];
            for (int i = 0; i < grid.length; i++) {
                List<MatrixPosition> list = listOfLists.get(i);
                grid[i] = list.toArray(new MatrixPosition[] {});
            }
            model = new MatrixModel(grid, new SpritePosition(1, 1));
        }

        return model;
    }

}

表示方向的基本枚举:

public enum Direction {
    UP, DOWN, LEFT, RIGHT
}

另一个用于表示网格中位置点的枚举,以及它是墙,coridor还是结尾以及从数字转换为MatrixPosition的静态方法:

public enum MatrixPosition {
    WALL(1), CORRIDOR(0), END(2);

    private int value;

    private MatrixPosition(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public static MatrixPosition getMatrixPosition(int value) {
        for (MatrixPosition position : MatrixPosition.values()) {
            if (value == position.getValue()) {
                return position;
            }
        }
        String text = "value of " + value;
        throw new IllegalArgumentException(text);
    }

    public static MatrixPosition getMatrixPosition(String strValue) {
        int value = -1;
        try {
            value = Integer.parseInt(strValue);
        } catch (NumberFormatException e) {
            String text = "NumberFormatException for strValue " + strValue;
            throw new IllegalAccessError(text);
        }
        return getMatrixPosition(value);
    }
}    

用于表示精灵位置的类,类似于java.awt.Point类但使用行和列字段而不是x和y:

public class SpritePosition {
    int row;
    int column;

    public SpritePosition(int row, int column) {
        this.row = row;
        this.column = column;
    }

    public int getRow() {
        return row;
    }

    public void setRow(int row) {
        this.row = row;
    }

    public int getColumn() {
        return column;
    }

    public void setColumn(int column) {
        this.column = column;
    }

    public void setRowColumn(int row, int column) {
        this.row = row;
        this.column = column;
    }

}    

该模型具有属性更改支持代码,因此它可以通知任何听取其状态更改的类。控制器将是听模型的类

import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;

public class MatrixModel {
    public static final String SPRITE_POINT = "sprite point";
    private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
    private MatrixPosition[][] grid;
    private SpritePosition spritePosition;

    public MatrixModel(MatrixPosition[][] grid, SpritePosition spritePosition) {
        this.grid = grid;
        this.spritePosition = spritePosition;
    }

    public int getRows() {
        return grid.length;
    }

    public int getColumns() {
        return grid[0].length;
    }

    public MatrixPosition getPosition(SpritePosition p) {
        return getPosition(p.row, p.column);
    }

    public MatrixPosition getPosition(int row, int col) {
        return grid[row][col];
    }

    public void setSpritePoint(SpritePosition spritePosition) {
        SpritePosition oldValue = this.spritePosition;
        SpritePosition newValue = spritePosition;
        this.spritePosition = spritePosition;
        pcSupport.firePropertyChange(SPRITE_POINT, oldValue, newValue);
    }

    public boolean isPointValid(SpritePosition p) {
        if (p.column < 0 || p.row < 0) {
            return false;
        }
        if (p.column >= grid[0].length || p.row >= grid.length) {
            return false;
        }
        return grid[p.row][p.column] == MatrixPosition.CORRIDOR;
    }

    public boolean isMoveValid(Direction direction) {
        int row = spritePosition.row;
        int column = spritePosition.column;
        switch (direction) {
        case UP:
            return isPointValid(new SpritePosition(row - 1, column));
        case DOWN:
            return isPointValid(new SpritePosition(row + 1, column));
        case LEFT:
            return isPointValid(new SpritePosition(row, column - 1));
        case RIGHT:
            return isPointValid(new SpritePosition(row, column + 1));
        default:
            return false;
        }
    }

    public void move(Direction direction) {
        if (!isMoveValid(direction)) {
            String text = "For move to " + direction + "spritePosition: " + spritePosition;
            throw new IllegalArgumentException(text);
        }
        int row = spritePosition.row;
        int column = spritePosition.column;
        switch (direction) {
        case UP:
            setSpritePoint(new SpritePosition(row - 1, column));
            break;
        case DOWN:
            setSpritePoint(new SpritePosition(row + 1, column));
            break;
        case LEFT:
            setSpritePoint(new SpritePosition(row, column - 1));
            break;
        case RIGHT:
            setSpritePoint(new SpritePosition(row, column + 1));
            break;

        default:
            break;
        }
    }

    public SpritePosition getSpritePosition() {
        return spritePosition;
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        pcSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        pcSupport.removePropertyChangeListener(listener);
    }

    public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
        pcSupport.addPropertyChangeListener(name, listener);
    }

    public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
        pcSupport.removePropertyChangeListener(name, listener);
    }
}    

控制器类,它在视图上设置键绑定,以便它可以监听按键,检查它们是否代表有效移动,如果是,则告诉模型进行移动。它还为模型添加了一个监听器,这样当状态发生变化时,它会告诉视图移动精灵

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.EnumMap;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;

public class Controller {
    private MatrixModel model;
    private View view;
    private Map<Direction, KeyStroke> dirKeyMap = new EnumMap<>(Direction.class);

    public Controller(MatrixModel model, View view) {
        this.model = model;
        this.view = view;

        dirKeyMap.put(Direction.DOWN, KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
        dirKeyMap.put(Direction.UP, KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
        dirKeyMap.put(Direction.LEFT, KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
        dirKeyMap.put(Direction.RIGHT, KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));

        model.addPropertyChangeListener(new ModelListener());
        setUpKeyBindings(view);
    }

    private void setUpKeyBindings(View view) {
        int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
        InputMap inputMap = view.getInputMap(condition);
        ActionMap actionMap = view.getActionMap();
        for (Direction dir : Direction.values()) {
            KeyStroke keyStroke = dirKeyMap.get(dir);
            hookUp(inputMap, actionMap, dir, keyStroke);
        }
    }

    private void hookUp(InputMap inputMap, ActionMap actionMap, Direction dir, KeyStroke key) {
        inputMap.put(key, key.toString());
        actionMap.put(key.toString(), new MoveAction(dir, model));
    }

    public MatrixModel getModel() {
        return model;
    }

    public View getView() {
        return view;
    }

    class ModelListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (MatrixModel.SPRITE_POINT.equals(evt.getPropertyName())) {
                SpritePosition p = model.getSpritePosition();
                view.setSpritePoint(p);
            }
        }
    }

}

@SuppressWarnings("serial")
class MoveAction extends AbstractAction {
    private Direction dir;
    private MatrixModel model;

    public MoveAction(Direction dir, MatrixModel model) {
        super(dir.toString());
        this.dir = dir;
        this.model = model;
    }

    public void actionPerformed(ActionEvent e) {
        if (model.isMoveValid(dir)) {
            model.move(dir);
        }
    }
}

最后,扩展JPanel的View类显示了迷宫和精灵:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class View extends JPanel {
    private static final int CELL_WIDTH = 20;
    private static final Color CORRIDOR_COLOR = Color.LIGHT_GRAY;
    private static final Color WALL_COLOR = Color.DARK_GRAY;
    private static final Color END_COLOR = Color.ORANGE;
    private static final Color SPRITE_COLOR = Color.RED;
    private static final int GAP = 1;
    private BufferedImage gridImg = null;
    private SpritePosition spritePosition;
    private JPanel mainPanel = new JPanel();

    public View(MatrixModel matrixModel) {
        gridImg = createImg(matrixModel);
        spritePosition = matrixModel.getSpritePosition();
    }

    public JPanel getMainPanel() {
        return mainPanel;
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet() || gridImg == null) {
            return super.getPreferredSize();
        }
        int prefW = gridImg.getWidth();
        int prefH = gridImg.getHeight();
        return new Dimension(prefW, prefH);
    }

    public void setSpritePoint(SpritePosition spritePosition) {
        this.spritePosition = spritePosition;
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (gridImg != null) {
            g.drawImage(gridImg, 0, 0, this);
        }
        g.setColor(SPRITE_COLOR);
        int y = spritePosition.row * CELL_WIDTH + GAP;
        int x = spritePosition.column * CELL_WIDTH + GAP;
        g.fillRect(x, y, CELL_WIDTH - 2 * GAP, CELL_WIDTH - 2 * GAP);
    }

    private BufferedImage createImg(MatrixModel matrixModel) {
        BufferedImage img = null;
        if (matrixModel != null && matrixModel.getRows() > 0) {
            int w = matrixModel.getColumns() * CELL_WIDTH;
            int h = matrixModel.getRows() * CELL_WIDTH;
            img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2 = img.createGraphics();
            for (int row = 0; row < matrixModel.getRows(); row++) {
                for (int col = 0; col < matrixModel.getColumns(); col++) {
                    MatrixPosition position = matrixModel.getPosition(row, col);
                    Color c = null;
                    switch (position) {
                    case CORRIDOR:
                        c = CORRIDOR_COLOR;
                        break;
                    case WALL:
                        c = WALL_COLOR;
                        break;
                    case END:
                        c = END_COLOR;
                        break;
                    }
                    g2.setColor(c);
                    int x = col * CELL_WIDTH;
                    int y = row * CELL_WIDTH;
                    g2.fillRect(x, y, CELL_WIDTH, CELL_WIDTH);
                }
            }
            g2.dispose();
        }
        return img;
    }

}