【问题标题】:Move circle around jpanel using keylistener使用keylistener在jpanel周围移动圆圈
【发布时间】:2015-07-18 09:03:20
【问题描述】:

好的,所以我正在尝试创建一个 Jpanel,它创建一个可以在屏幕上移动的圆圈。我已经来回走了一段时间,似乎无法弄清楚如何让实际的东西为我移动。

package astroidlab;

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

public class MainFrame {
    public static void main(String[] args) {
      //components
    JFrame jf = new JFrame();
    PaintObjects po = new PaintObjects();


    jf.setLayout(new BorderLayout());
    jf.add(po, BorderLayout.CENTER);

    jf.setVisible(true);
    jf.setSize(300, 300);
    jf.setLocationRelativeTo(null);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

  }
}

这是框架类。 ^^

package astroidlab;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JPanel;
import javax.swing.Timer;

public class PaintObjects extends JPanel implements ActionListener{
//global variable
Ship s = new Ship();

//constructor
public PaintObjects() {
    super();

    Timer t = new Timer(50, this);
    t.start();
}

@Override
public void paintComponent(Graphics g) {
        super.paintComponents(g);
        g.setColor(Color.BLACK);

        g.fillOval(s.getXpos(),  s.getYpos(),  s.getHeight(),  s.getWidth());

}

@Override
public void actionPerformed(ActionEvent ae) {
    int xpos = s.getXpos();
    int ypos = s.getYpos();


    repaint();
}
}

上面的类应该绘制对象并更新它们。它确实绘制了椭圆形,但我似乎无法融入我的下一堂课。

package astroidlab;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;

public class MoveShip extends JFrame{
Ship s = new Ship();

public MoveShip() {

    ballMover bm = new ballMover();
    this.addKeyListener(bm);

}

private class ballMover implements KeyListener {

    @Override
    public void keyPressed(KeyEvent ke) {
        if(ke.getKeyCode() == 37) {
            s.goLeft();
        }
        if(ke.getKeyCode() == 39) {
            s.goRight();
        }
        if(ke.getKeyCode() == 38) {
            s.goUp();
        }
        if(ke.getKeyCode() == 40) {
            s.goDown();
        }
    }

    @Override
    public void keyReleased(KeyEvent ke) {
    }

    @Override
    public void keyTyped(KeyEvent ke) {
    }

}

}

上面的课程似乎是我出错的地方。我对图形没有经验,所以我觉得我只是错过了一些简单的东西。

package astroidlab;

public class Ship {
//fields
int xpos = 0;
int ypos = 0;
int height = 20;
int width = 20;

public Ship() {
    super();
}

//move methods
public  void goLeft() {
    xpos -= 2;
    System.out.println("xpos: " + xpos + " ypos: " + ypos);
}
public  void goRight() {
    xpos += 2;
    System.out.println("xpos: " + xpos + " ypos: " + ypos);
}

public  void goUp() {
    ypos -= 2;
    System.out.println("xpos: " + xpos + " ypos: " + ypos);
}
public  void goDown() {
    ypos += 2;
    System.out.println("xpos: " + xpos + " ypos: " + ypos);
}

//get methods
public int getXpos() {
    return xpos;
}
public int getYpos() {
    return ypos;
}
public int getHeight() {
    return height;
}
public int getWidth() {
    return width;
}

//set methods
public void setXpos() {
    this.xpos = xpos;
}
public void setYpos() {
    this.ypos = ypos;
}
public void setHeight() {
    this.height = height;
}
public void setWidth() {
    this.width = width;
}

}

然后这个类会跟踪椭圆的位置,并在按下一个键时更新它。 (或者应该)

无论如何,我们将不胜感激。我确定我只是在做一些菜鸟错误。提前致谢。

【问题讨论】:

    标签: java swing graphics actionlistener keylistener


    【解决方案1】:
    1. 上面的代码从不使用MoveShip 类。也许您打算在 main 方法中创建此类的实例,而不仅仅是 JFrame
    2. 如果您更改某物的坐标(在本例中为 KeyListener 方法中的 Ship),并且想要重新绘制以使坐标更改生效,则应在您希望绘制的对象上显式调用 repaint(在这种情况下PaintObjects)。
    3. MoveShipPaintObjects 都包含它们自己的 Ship 实例 - 如果一个实例移动它不会影响另一个实例。相反,创建一个可以在两个类之间共享的实例。
    4. 要触发KeyListener,组件必须具有焦点。您可以考虑使用KeyBindings

    【讨论】:

    • 1) 感谢您的帮助,看来我没有正确使用 MoveShip。 2) 我不是已经通过在 PaintObjects 中使用 repaint() 来做到这一点了吗? (我只是想澄清一下) 3)这是有道理的,但是如何创建两个类可以使用的实例? 4)注意,虽然使用 KeyListener 只是这个项目的必要条件。
    • 没关系,看来我自己想通了。我只是在每次按键后添加了 repaint() 并且我能够弄清楚如何使实例工作。非常感谢您的帮助。
    【解决方案2】:

    我使用键绑定而不是键侦听器。使用键绑定的好处是您可以将 WASD 键(对于左手玩家)和箭头键(对于右手玩家)绑定到同一个 AbstractAction。

    这是我创建的 GUI。

    我没有进行任何错误检查以确保圆圈留在 JPanel 绘图区域中。

    1. 我通过调用 main 方法中的 SwingUtilities invokeLater 方法在 Event Dispatch thread 上启动了 Swing GUI。

    2. 我使用了 JFrame。覆盖 Swing 组件(或任何 Java 类)的唯一时间是当您想要覆盖一个或多个类方法时。

    3. setKeyBindings 方法将 WASD 键和箭头键设置为 AbstractAction 方法。

    这是代码。

    package com.ggl.testing;
    
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Point;
    import java.awt.event.ActionEvent;
    
    import javax.swing.AbstractAction;
    import javax.swing.InputMap;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.KeyStroke;
    import javax.swing.SwingUtilities;
    
    public class MoveCircle implements Runnable {
    
        private JFrame frame;
    
        @Override
        public void run() {
            frame = new JFrame("Move The Circle");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            CirclePanel linePanel = new CirclePanel();
            setKeyBindings(linePanel);
            frame.add(linePanel);
    
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        private void setKeyBindings(CirclePanel circlePanel) {
            InputMap inputMap = circlePanel
                    .getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
            inputMap.put(KeyStroke.getKeyStroke("W"), "up arrow");
            inputMap.put(KeyStroke.getKeyStroke("S"), "down arrow");
            inputMap.put(KeyStroke.getKeyStroke("A"), "left arrow");
            inputMap.put(KeyStroke.getKeyStroke("D"), "right arrow");
    
            inputMap.put(KeyStroke.getKeyStroke("UP"), "up arrow");
            inputMap.put(KeyStroke.getKeyStroke("DOWN"), "down arrow");
            inputMap.put(KeyStroke.getKeyStroke("LEFT"), "left arrow");
            inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "right arrow");
    
            inputMap = circlePanel.getInputMap(JPanel.WHEN_FOCUSED);
            inputMap.put(KeyStroke.getKeyStroke("UP"), "up arrow");
            inputMap.put(KeyStroke.getKeyStroke("DOWN"), "down arrow");
            inputMap.put(KeyStroke.getKeyStroke("LEFT"), "left arrow");
            inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "right arrow");
    
            circlePanel.getActionMap().put("up arrow",
                    new ArrowAction(circlePanel, new Point(0, -10)));
            circlePanel.getActionMap().put("down arrow",
                    new ArrowAction(circlePanel, new Point(0, 10)));
            circlePanel.getActionMap().put("left arrow",
                    new ArrowAction(circlePanel, new Point(-10, 0)));
            circlePanel.getActionMap().put("right arrow",
                    new ArrowAction(circlePanel, new Point(10, 0)));
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new MoveCircle());
        }
    
        public class CirclePanel extends JPanel {
    
            private static final long serialVersionUID = 2504617322590404776L;
    
            private Point lastPoint;
    
            public CirclePanel() {
                int width = 400;
                this.setPreferredSize(new Dimension(width, width));
                this.lastPoint = new Point(width / 2, width / 2);
            }
    
            public void addPoint(int x, int y) {
                lastPoint = new Point(x, y);
            }
    
            public Point getPreviousPoint() {
                return lastPoint;
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
    
                g.setColor(Color.RED);
                g.fillOval(lastPoint.x - 20, lastPoint.y - 20, 40, 40);
            }
        }
    
        public class ArrowAction extends AbstractAction {
    
            private static final long serialVersionUID = 8463453082541763265L;
    
            private CirclePanel circlePanel;
    
            private Point movePoint;
    
            public ArrowAction(CirclePanel circlePanel, Point movePoint) {
                this.circlePanel = circlePanel;
                this.movePoint = movePoint;
            }
    
            @Override
            public void actionPerformed(ActionEvent event) {
                Point p = circlePanel.getPreviousPoint();
                p.x += movePoint.x;
                p.y += movePoint.y;
                circlePanel.addPoint(p.x, p.y);
                circlePanel.repaint();
            }
    
        }
    
    }
    

    【讨论】:

    • 感谢您的帮助,尽管您的程序对我来说似乎有点太高级了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    相关资源
    最近更新 更多