当前位置: 首页 > 面试题库 >

无法重绘我的JFrame / JPanel

从元明
2023-03-14
问题内容

我创建了一个程序,可以在屏幕上移动一个球。我以前把所有内容都放在一个类中,但认为它看起来太乱了,所以我将其分为三个不同的类:Main
…初始化所有内容,Game
…绘制所有内容并为一个JPanel,AL则为一个KeyListener(这也是问题所在)。问题是,无论我尝试将其传递给我的类,我都无法从AL类获得重绘程序。有人能帮忙吗?这是我的三个班级:

import java.awt.Color;

import javax.swing.JFrame;

public class Main {
    static Game game;
    static JFrame frame;

public static void main(String[] args) {
    game = new Game();
    frame = new JFrame();

    frame.getContentPane().add(game);
    frame.addKeyListener(new AL(game, frame));
    frame.setTitle("Game");
    frame.setSize(500, 500);
    frame.setResizable(true);
    frame.setVisible(true);
    frame.setBackground(Color.BLACK);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

--

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Game extends JPanel implements Runnable {
    int x, y, xCoord, yCoord;
    private Image dbImage;
    private Graphics dbg;
    JFrame frame;

public void changeCoord() {
    x += xCoord;
    y += yCoord;
    if (x <= 20) {
        x = 20;
    }
    if (x >= 480) {
        x = 480;
    }
    if (y <= 40) {
        y = 40;
    }
    if (y >= 480) {
        y = 480;
    }
}

public void setXCoord(int xcoord) {
    xCoord = xcoord;
}

public void setYCoord(int ycoord) {
    yCoord = ycoord;
}

public static void main(String[] args) {
    Game game = new Game();
    Thread t = new Thread(game);
    t.start();
}

public Game() {
    x = 250;
    y = 250;

}

@Override
public void paintComponent(Graphics g) {
    g.setColor(Color.GREEN);
    g.fillOval(x, y, 15, 15);
}

@Override
public void paint(Graphics g) {
    dbImage = createImage(getWidth(), getHeight());
    dbg = dbImage.getGraphics();
    paintComponent(dbg);
    g.drawImage(dbImage, 0, 0, this);
}

@Override
public void run() {
    try {
        while (true) {
            changeCoord();
            Thread.sleep(30);
        }
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

}

--

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;

public class AL extends KeyAdapter {
    Game game;
    JFrame frame;

public AL(Game game, JFrame frame) {
    this.game = game;
    this.frame = frame;
}

@Override
public void keyPressed(KeyEvent e) {
    int keyCode = e.getKeyCode();
    if (keyCode == e.VK_LEFT) {
        game.setXCoord(-1);
    }
    if (keyCode == e.VK_RIGHT) {
        game.setXCoord(+1);
    }
    if (keyCode == e.VK_UP) {
        game.setYCoord(-1);
    }
    if (keyCode == e.VK_DOWN) {
        game.setYCoord(+1);
    }
    game.repaint();
}

@Override
public void keyReleased(KeyEvent e) {
    int keyCode = e.getKeyCode();
    if (keyCode == e.VK_LEFT) {
        game.setXCoord(0);
    }
    if (keyCode == e.VK_RIGHT) {
        game.setXCoord(0);
    }
    if (keyCode == e.VK_UP) {
        game.setYCoord(0);
    }
    if (keyCode == e.VK_DOWN) {
        game.setYCoord(0);
    }
    game.repaint();

}

}

问题答案:

让我们从显而易见的…开始。

这是有问题的…

@Override
public void paintComponent(Graphics g) {
    g.setColor(Color.GREEN);
    g.fillOval(x, y, 15, 15);
}

@Override
public void paint(Graphics g) {
    dbImage = createImage(getWidth(), getHeight());
    dbg = dbImage.getGraphics();
    paintComponent(dbg);
    g.drawImage(dbImage, 0, 0, this);
}

现在已经不需要在Swing组件中实现双缓冲了。另外,通过不将paint方法称为super方法,您正在破坏绘画合同

整个事情应该是…

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(Color.GREEN);
    g.fillOval(x, y, 15, 15);
}

有关更多详细信息,请参见AWT中的绘画和摇摆和执行自定义绘画。

KeyListener因存在问题而众所周知。仅当注册到的组件可操作并且具有键盘焦点时,它才会引发键事件。JPanel默认情况下,A
不可聚焦。在尝试并使其具有针对性(让您非常失望)之前,您应该改用Key Bindings
API,该API旨在克服以下限制:KeyListener

作为一个基本的例子…

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new Game());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Game extends JPanel {

        int x, y, xCoord, yCoord;

        public Game() {
            x = 250;
            y = 250;
            addKeyBinding(KeyEvent.VK_LEFT, "move.left", new MoveAction(this, -1, 0));
            addKeyBinding(KeyEvent.VK_RIGHT, "move.right", new MoveAction(this, 1, 0));
            addKeyBinding(KeyEvent.VK_UP, "move.up", new MoveAction(this, 0, -1));
            addKeyBinding(KeyEvent.VK_DOWN, "move.down", new MoveAction(this, 0, 1));
        }

        protected void addKeyBinding(int keyCode, String name, Action action) {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
        }

        protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
            InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap actionMap = getActionMap();
            inputMap.put(keyStroke, name);
            actionMap.put(name, action);
        }

        public void changeCoord() {
            x += xCoord;
            y += yCoord;
            if (x <= 20) {
                x = 20;
            }
            if (x >= 480) {
                x = 480;
            }
            if (y <= 40) {
                y = 40;
            }
            if (y >= 480) {
                y = 480;
            }

            repaint();
        }

        public void setXCoord(int xcoord) {
            xCoord = xcoord;
            changeCoord();
        }

        public void setYCoord(int ycoord) {
            yCoord = ycoord;
            changeCoord();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(480, 480);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.GREEN);
            g.fillOval(x, y, 15, 15);
        }

    }

    public class MoveAction extends AbstractAction {

        private int xDelta;
        private int yDelta;

        // I'd prefer an interface with just the "move" methods, but
        // that's more time I don't have
        private Game game;

        public MoveAction(Game game, int xDelta, int yDelta) {
            this.xDelta = xDelta;
            this.yDelta = yDelta;
            this.game = game;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            game.setXCoord(xDelta);
            game.setYCoord(yDelta);
        }

    }
}

但是,等等,那不完全是您想要的(相信我,我是互联网上的糊涂人;)),一个更好的例子可能是…

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Main {

    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new Game());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

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

    public class Game extends JPanel {

        int x, y, xCoord, yCoord;

        private Set<Direction> movement;

        public Game() {
            x = 250;
            y = 250;

            movement = new HashSet<>(4);

            addKeyPressedBinding(KeyEvent.VK_LEFT, "left.pressed", new MoveAction(movement, Direction.LEFT, true));
            addKeyReleasedBinding(KeyEvent.VK_LEFT, "left.released", new MoveAction(movement, Direction.LEFT, false));

            addKeyPressedBinding(KeyEvent.VK_RIGHT, "right.pressed", new MoveAction(movement, Direction.RIGHT, true));
            addKeyReleasedBinding(KeyEvent.VK_RIGHT, "right.released", new MoveAction(movement, Direction.RIGHT, false));

            addKeyPressedBinding(KeyEvent.VK_UP, "up.pressed", new MoveAction(movement, Direction.UP, true));
            addKeyReleasedBinding(KeyEvent.VK_UP, "up.released", new MoveAction(movement, Direction.UP, false));

            addKeyPressedBinding(KeyEvent.VK_DOWN, "down.pressed", new MoveAction(movement, Direction.DOWN, true));
            addKeyReleasedBinding(KeyEvent.VK_DOWN, "down.released", new MoveAction(movement, Direction.DOWN, false));

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    changeCoord();
                }
            });
            timer.start();
        }

        protected void addKeyBinding(int keyCode, String name, Action action) {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
        }

        protected void addKeyPressedBinding(int keyCode, String name, Action action) {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, false), name, action);
        }

        protected void addKeyReleasedBinding(int keyCode, String name, Action action) {
            addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, true), name, action);
        }

        protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
            InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap actionMap = getActionMap();
            inputMap.put(keyStroke, name);
            actionMap.put(name, action);
        }

        public void changeCoord() {

            if (movement.contains(Direction.UP)) {
                y--;
            } else if (movement.contains(Direction.DOWN)) {
                y++;
            }
            if (movement.contains(Direction.LEFT)) {
                x--;
            } else if (movement.contains(Direction.RIGHT)) {
                x++;
            }

            x += xCoord;
            y += yCoord;
            if (x <= 20) {
                x = 20;
            }
            if (x >= 480) {
                x = 480;
            }
            if (y <= 40) {
                y = 40;
            }
            if (y >= 480) {
                y = 480;
            }

            repaint();
        }

        public void setXCoord(int xcoord) {
            xCoord = xcoord;
            changeCoord();
        }

        public void setYCoord(int ycoord) {
            yCoord = ycoord;
            changeCoord();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(480, 480);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.GREEN);
            g.fillOval(x, y, 15, 15);
        }

    }

    public class MoveAction extends AbstractAction {

        private Set<Direction> movement;
        private Direction direction;
        private boolean pressed;

        public MoveAction(Set<Direction> movement, Direction direction, boolean pressed) {
            this.movement = movement;
            this.direction = direction;
            this.pressed = pressed;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (pressed) {
                movement.add(direction);
            } else {
                movement.remove(direction);
            }
        }

    }
}

这样做只是在按下某个键时激活一个标志(并在释放它时将其禁用),然后在Swing中Timer,我们检查哪些键是“活动的”并更新球的位置。

这样做是消除了第一次按下并按住某个键时由操作系统引起的键“口吃”。在第一个键和重复的键事件之间插入一个延迟。相反,我们只是根据需要打开和关闭该标志。

它还允许您同时在两个方向(水平和垂直)上移动

了解Swing中的并发性以及如何使用Swing计时器以了解更多详细信息



 类似资料:
  • 我创建了一个程序,只需在屏幕上移动一个球。我以前把它都放在一节课上,但我觉得它看起来太乱了,所以我把它分成了三个不同的课:主课。。。初始化一切,游戏。。。它描绘一切,是一个JPanel,AL是一个KeyListener(这也是问题所在)。问题是,我无法让程序从我的AL类重新绘制,无论我试图传递什么。有人能帮忙吗?以下是我的三门课: - -

  • 问题内容: 我正在尝试制作一个在鼠标本地化处绘制一个圆的简单Java程序,它获取了鼠标的X和Y坐标,但是它没有绘制任何内容,我试图绘制一个String,一个圆和一条线,但是没有任何效果,我稍微修改了代码,但仍然无法正常工作 问题答案: 不要直接在上执行自定义绘画。如果可以,请始终在替代方法上进行操作。 为此,请勿使用无限循环。有用于Mouse Motion收听的

  • 编辑:当我拖动边框时,某种刷新被发送,我需要弄清楚并手动发送相同的刷新。 请注意,我已经尝试使用revalidate()和repaint()。 当使用JFrame和JPanel来显示一个框架时,我试图使框架的大小易于改变。 null 此外,一个重要的注意事项是,当您拖动边框时,白条会消失,并正确地重新加载/刷新内容(即使您只是少量拖动)

  • 问题内容: 我知道这是我的错误。我的问题是,为什么这不起作用,我想念的是什么,我可以称其为方法而不是类,因此我假设他们的第三类有问题吗? 第1类: } 第2类: 第3类,这是我不能在jframe上使用的绘画: } 问题答案: 您的问题是您滥用继承。您的JVMDiagram正在扩展JVMComponent,但不应该。是的,您获得了JVMComponent的getWidth()和getHeight()

  • 我正在做一个游戏,我试图在JFrame中添加一个JPanel。我有一个单独的类来扩展JPanel,我创建了一个新的对象来扩展JPanel。 但是,我得到了这个错误:“类型容器中的方法add(Component)不适用于参数(mainMenu)”(mainMenu是扩展JPanel的类)。 (JPanel类)公共类mainMenu扩展JPanel{ 我希望这样可以向我的JFrame添加一个JPane

  • 问题内容: 我无法在JFrame上绘制此椭圆形。 框架显示,但其中未绘制任何内容。我在这里做错了什么? 问题答案: 您创建了一个静态方法,该方法不会覆盖paint方法。现在,其他人已经指出,您需要覆盖paintComponent等。但是,为了快速修复,您需要执行以下操作: 但是,正如其他人指出的那样,在JFrame上进行绘制非常棘手。最好使用JPanel。