How does one properly handle keypresses and repainting of a JComponent in the context of moving a ball around a screen?

前端 未结 3 1342
执笔经年
执笔经年 2020-12-11 23:28

I thought I would try and write a program that would paint a ball, and when the arrow keys are pressed, would move the ball around the screen in the direction pressed. First

相关标签:
3条回答
  • 2020-12-11 23:40

    Please do have a look at this code example :

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class PaintingPanel
    {
        private CustomPanel drawingArea;
        private ActionMap actionMap;
        private int x;
        private int y;
    
        private enum Direction 
        {
            UP(KeyEvent.VK_UP),
            DOWN(KeyEvent.VK_DOWN),
            LEFT(KeyEvent.VK_LEFT),
            RIGHT(KeyEvent.VK_RIGHT);
    
            public int key;
    
            private Direction(int key)
            {
                this.key = key;
            }
    
            public int getKey()
            {
                return key;
            }
        }
    
        private class PanelAction extends AbstractAction
        {
            private Direction arrow;
    
            public PanelAction(Direction a)
            {
                arrow = a;
            }
    
            @Override
            public void actionPerformed(ActionEvent ae)
            {
                switch(arrow)
                {
                    case UP:
                        y -= 1;
                        break;
                    case DOWN:
                        y += 1;
                        break;
                    case LEFT:
                        x -= 1;
                        break;
                    case RIGHT:
                        x += 1;
                        break;
                }
                drawingArea.setValues(x, y);
            }
        }
    
        public PaintingPanel()
        {
            x = y = 5;
        }
    
        private void displayGUI()
        {
            JFrame frame = new JFrame("Painting Panel");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            drawingArea = new CustomPanel();
            int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
            InputMap inputMap = drawingArea.getInputMap(condition);
            actionMap = drawingArea.getActionMap();
    
            for (Direction arrow : Direction.values())
            {
                int key = arrow.getKey();
                String name = arrow.name();
                inputMap.put(KeyStroke.getKeyStroke(
                                key, 0), name);
                actionMap.put(name, new PanelAction(arrow));                    
            }
    
            frame.setContentPane(drawingArea);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        public static void main(String... args)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    new PaintingPanel().displayGUI();
                }
            });
        }
    }
    
    class CustomPanel extends JPanel
    {
        private final int SIZE = 500;
        private int x;
        private int y;
        private String text = "Hello World!";
    
        public CustomPanel()
        {
            x = y = 5;
            setOpaque(true);
            setBackground(Color.WHITE);
        }
    
        public void setValues(int x, int y)
        {
            this.x = x;
            this.y = y;
            repaint();
        }
    
        @Override
        public Dimension getPreferredSize()
        {
            return (new Dimension(SIZE, SIZE));
        }
    
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.setColor(Color.GREEN.darker());
            g.fillOval(x, y, 50, 50);
        }
    }
    
    0 讨论(0)
  • 2020-12-11 23:44

    You can use the KeyboardFocusManager to listen for keystrokes of the arrow keys and update the position of the ball. Here is the reworked code:

    class BallFrame extends JFrame {
        private static final int DEFAULT_WIDTH = 500;
        private static final int DEFAULT_HEIGHT = 500;
        final BallComponent ball = new BallComponent();
    
        public BallFrame() {
            super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            super.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
            super.setResizable(false);
            super.add(ball);
            super.setVisible(true);
    
            KeyboardFocusManager.getCurrentKeyboardFocusManager()
                    .addKeyEventDispatcher(new KeyEventDispatcher() {
                        @Override
                        public boolean dispatchKeyEvent(KeyEvent e) {
                            if (e.getKeyCode() == KeyEvent.VK_UP)
                                ball.move(0, -10);
                            if (e.getKeyCode() == KeyEvent.VK_RIGHT)
                                ball.move(10, 0);
                            if (e.getKeyCode() == KeyEvent.VK_LEFT)
                                ball.move(-10, 0);
                            if (e.getKeyCode() == KeyEvent.VK_DOWN)
                                ball.move(0, 10);
                            return false;
                        }
                    });
    
        }
    }
    

    And for BallComponent class:

    static class BallComponent extends JComponent {
        private double x = 225;
        private double y = 225;
        private Ellipse2D.Double ellipse = new Ellipse2D.Double(x, y, 50, 50);
    
        public void move(int dX, int dY) {
            x += dX;
            y += dY;
            ellipse = new Ellipse2D.Double(x, y, 50, 50);
            repaint();
        }
    
        public void paintComponent(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.fill(ellipse);
        }
    }
    
    0 讨论(0)
  • 2020-12-11 23:49

    It seems that you never initialized actionPress - try adding this to your BallComponent constructor:

    actionPress = new ActionPress();
    

    ie, your constructor would look like this

    public BallComponent()
    {
        super();
        super.setFocusable(true);
    
        InputMap imap1 = this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        imap1.put(KeyStroke.getKeyStroke("ctrl Y"), "keyUp1");
        InputMap imap2 = this.getInputMap(JComponent.WHEN_FOCUSED);
        imap1.put(KeyStroke.getKeyStroke("ctrl Y"), "keyUp2");
        InputMap imap3 = this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);   
        imap1.put(KeyStroke.getKeyStroke("ctrl Y"), "keyUp3");
    
        actionPress = new ActionPress();
        ActionMap amap = this.getActionMap();
        amap.put("keyUp1", actionPress);
        amap.put("keyUp2", actionPress);    
        amap.put("keyUp3", actionPress);
    }
    
    0 讨论(0)
提交回复
热议问题