Можно ли использовать paintComponent() в классе AbstractAction?

Я пытаюсь создать программу, которая создает JPanel, и когда пользователь нажимает W, A, S и D, нарисованный куб будет перемещаться по окну (на определенную величину при каждом нажатии клавиши), Я создал класс MoveCubeUp и переопределил в нем метод paintComponent, чтобы перекрасить куб при его вызове, но он не будет работать. Может кто-нибудь объяснить, почему?

public MyPanel(){
    …
    MoveSquareUp m=new MoveSquareUp(squareX, squareY);
    getInputMap().put(KeyStroke.getKeyStroke(("W"), "pressed"));
getActionMap().put("pressed", m)
}
class MoveSquareUp extends AbstractAction{
    public int squareXX, squareYY;
    public moveSquare(){
    squareXX=squareX+5;
    }
//I define the paintComponent method to draw the rectangle with its set height        
//at squareXX, squareYY
//action method is null (I am still trying to figure out binding keys to    
//actions but the paintComponent not working is preventing that
}

Я извиняюсь, если это было плохо отформатировано. 1-е сообщение:/ Нужно ли определять метод рисования в классе, который расширяет JFrame, и если да, то как я могу использовать его с классом abstractAction (или как вообще избежать класса AbstractAction)?

1 ответ

Решение

Суть вашей проблемы в том, что вам нужно научиться отделять вашу модель от вашего взгляда от вашего контроля. Здесь модель - это местоположение вашего спрайта, представление - это графический интерфейс, который рисует эту позицию, и элемент управления будет содержать действия, включая ваше AbstractAction, и все они должны быть отделены друг от друга, если это возможно.

Итак, чтобы ответить на ваш прямой вопрос - никакой paintComponent определенно не должен быть внутри AbstractAction, поскольку первый является ключевой частью представления, а второй - ключевой частью элемента управления. Вместо этого сделайте так, чтобы ваше представление отражало состояние модели, и состояние модели будет изменяться элементом управления (действиями).

Что касается вашего другого вопроса, должны ли все методы рисования быть частью JFrame: ни один из методов рисования не должен быть в классе, расширяющем JFrame, так как этот класс является сложным классом, который создает окно верхнего уровня и несколько подкомпонентов для отображения вашего GUI, и если вы переопределяете его рисование, вы можете плохо выполнять рисование подкомпонентов. Вместо этого нарисуйте метод paintComponent класса, расширяющего JPanel, а затем отобразите этот объект в JFrame.

Например:

package pkg3;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

public class GamePanel extends JPanel {
    private static final int ANIMATION_DELAY = 15;
    private final int HEIGHT = 400;
    private final int WIDTH = 600;
    private Square square;
    private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
    private Map<Integer, Direction> keyToDir = new HashMap<>();
    // !! private Circle circle;
    private Timer animationTimer;

    public GamePanel() {
        for (Direction dir : Direction.values()) {
            dirMap.put(dir, Boolean.FALSE);
        }
        keyToDir.put(KeyEvent.VK_UP, Direction.UP);
        keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN);
        keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT);
        keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT);
        setKeyBindings();
        setBackground(Color.white);
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setFocusable(true);
        square = new Square();
        animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener());
        animationTimer.start();
    }

    private void setKeyBindings() {
        int condition = WHEN_IN_FOCUSED_WINDOW;
        final InputMap inputMap = getInputMap(condition);
        final ActionMap actionMap = getActionMap();
        boolean[] keyPressed = { true, false };
        for (Integer keyCode : keyToDir.keySet()) {
            Direction dir = keyToDir.get(keyCode);
            for (boolean onKeyPress : keyPressed) {
                boolean onKeyRelease = !onKeyPress; // to make it clear how
                                                    // bindings work
                KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0, onKeyRelease);
                Object key = keyStroke.toString();
                inputMap.put(keyStroke, key);
                actionMap.put(key, new KeyBindingsAction(dir, onKeyPress));
            }
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        square.display(g);
    }

    private class AnimationListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent evt) {
            boolean repaint = false;
            for (Direction dir : Direction.values()) {
                if (dirMap.get(dir)) {
                    square.move(dir);
                    repaint = true;
                }
            }
            if (repaint) {
                repaint();
            }
        }
    }

    private class KeyBindingsAction extends AbstractAction {
        private Direction dir;
        boolean pressed;

        public KeyBindingsAction(Direction dir, boolean pressed) {
            this.dir = dir;
            this.pressed = pressed;
        }

        @Override
        public void actionPerformed(ActionEvent evt) {
            dirMap.put(dir, pressed);
        }
    }

    private static void createAndShowGUI() {
        GamePanel gamePanel = new GamePanel();
        JFrame frame = new JFrame("GamePanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(gamePanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        gamePanel.requestFocusInWindow();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

enum Direction {
    UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
    private int incrX;
    private int incrY;

    private Direction(int incrX, int incrY) {
        this.incrX = incrX;
        this.incrY = incrY;
    }

    public int getIncrX() {
        return incrX;
    }

    public int getIncrY() {
        return incrY;
    }
}

class Square {
    private int x = 0;
    private int y = 0;
    private int w = 20;
    private int h = w;
    private int step = 1;
    private Color color = Color.red;
    private Color fillColor = new Color(255, 150, 150);
    private Stroke stroke = new BasicStroke(3f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);

    public void display(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(fillColor);
        g2d.fillRect(x, y, w, h);
        g2d.setStroke(stroke);
        g2d.setColor(color);
        g2d.drawRect(x, y, w, h);
        g2d.dispose();
    }

    public void setStep(int step) {
        this.step = step;
    }

    public void move(Direction dir) {
        x += step * dir.getIncrX();
        y += step * dir.getIncrY();
    }

}
Другие вопросы по тегам