有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程Java使对象在按住按钮的同时移动

按下按钮时如何使JPanel移动,松开按钮时如何停止。我试过使用线程。用Runnable和类似的方式启动()。我总是遇到错误。有人能帮我吗


共 (3) 个答案

  1. # 1 楼答案

    像这样的事情可能会做你想做的事情:

    有一个包含

    private JPanel movingJPanel = new JPanel(); // Declare this however
    
    public void paint(Graphics g) {
        //draw background first
        Point drawAt;
        syncronised (sync) {
            drawAt = this.drawAt
        }
        Dimension size = movingJPanel.getPreferredSize();
        Graphics paintWith = g.create(movingJPanel);
        movingJPanel.paint(paintWith);
    }
    
    private Point moveFrom = new Point(0, 0);
    private Point moveTo = new Point(100, 100);    
    private Point drawAt = new Point(0, 0);
    private int steps = 35;
    private int step = 0;
    private long timeBetweenSteps = 50L;
    private Object sync = new Object();
    private boolean moving = false;
    
    private Thread thread = new Thread(new Runnable() {
        public void run() {
            while (!Thread.interrupted()) {
                synchronized(sync) {
                    if (moving && step < steps) {
                        step++;
                        drawAt = new Point((moveTo.x - moveFrom.x) * step / steps,
                                (moveTo.y - moveFrom.y) * step / steps)
                        drawMovingPanelIn.repaint();
                        sync.wait(timeBetweenSteps);
                    }
                }
            }
        }
    });
    
    public void start() {
        synchronized(sync) {
            moving = true;
            sync.notify();
        }
    }
    
    public void start() {
        synchronized(sync) {
            moving = false;
        }
    }
    
    public void reset() {
        syncronized(sync) {
            steps = 0;
        }
    }
    

    以及一个包含

    thread.start();
    

    现在,从添加到按钮的MouseListener的mousePressed和MouseReleased方法中调用start()stop()方法

  2. # 2 楼答案

    你需要考虑一些重要的因素

    1. 按钮不是为这种方式设计的。它们被设计成在被点击(按下和释放)时触发和操作事件,所以你不能使用普通的操作API。幸运的是,还有其他方法可以确定按钮的状态。本例在ButtonModel上使用ChangeListener,并根据模型的状态采取操作
    2. 组件通常由布局管理器控制。这意味着为了能够移动组件,我们需要关闭它(也称为nullabsolute布局)。通常情况下,我不鼓励这样做,但这是唯一可行的方法。然而移除布局管理器后,您将负责确保组件的位置和大小正确。。。这项工作不能掉以轻心。更多地了解你想要实现的目标会得到更好的答案
    3. 当按钮被“按下”时,我们需要一种方法来确定移动组件的方式。本例使用一个简单的enum来确定移动组件的方向。您可以同样轻松地使用x/yDelta并直接修改组件x/y位置。两者都可以
    4. Swing是一个单线程环境。也就是说,对UI的所有交互和修改都将在事件调度线程的上下文中执行。但任何阻止EDT的操作都将阻止UI开始更新或任何新事件开始处理。这意味着,为了移动组件,我们不能简单地使用while-loop,因为它永远不会结束(不会处理新事件)。相反,本例使用了一个javax.swing.Timer,它在后台等待,并在EDT上下文中的每个滴答上引发一个ActionEvent。如果出现滴答声,我们将修改面板的位置

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.ButtonModel;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    
    public class MovePane {
    
        public static void main(String[] args) {
            new MovePane();
        }
    
        public MovePane() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public enum Direction {
    
            None, Up, Down, Left, Right;
        }
    
        public class TestPane extends JPanel {
    
            private JPanel mobby;
            private Timer moveTimer;
            private Direction moveDirection = Direction.None;
    
            public TestPane() {
                mobby = new JPanel();
                mobby.setBackground(Color.RED);
                mobby.setSize(50, 50);;
                setLayout(new BorderLayout());
                JPanel pool = new JPanel(null);
                pool.add(mobby);
                add(pool);
                JPanel buttons = new JPanel(new GridBagLayout());
    
                JButton up = new JButton("Up");
                JButton dwn = new JButton("Down");
                JButton lft = new JButton("Left");
                JButton rgt = new JButton("Right");
    
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.fill = GridBagConstraints.HORIZONTAL;
                gbc.gridx = 1;
                gbc.gridy = 0;
                buttons.add(up, gbc);
                gbc.gridx = 1;
                gbc.gridy = 2;
                buttons.add(dwn, gbc);
                gbc.gridx = 0;
                gbc.gridy = 1;
                buttons.add(lft, gbc);
                gbc.gridx = 2;
                gbc.gridy = 1;
                buttons.add(rgt, gbc);
    
                add(buttons, BorderLayout.SOUTH);
    
                up.getModel().addChangeListener(new ChangeHandler(Direction.Up));
                dwn.getModel().addChangeListener(new ChangeHandler(Direction.Down));
                lft.getModel().addChangeListener(new ChangeHandler(Direction.Left));
                rgt.getModel().addChangeListener(new ChangeHandler(Direction.Right));
    
                moveTimer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Container parent = mobby.getParent();
                        Rectangle bounds = mobby.getBounds();
                        switch (moveDirection) {
                            case Up:
                                bounds.y ;
                                break;
                            case Down:
                                bounds.y++;
                                break;
                            case Left:
                                bounds.x ;
                                break;
                            case Right:
                                bounds.x++;
                                break;
                        }
    
                        if (bounds.x < 0) {
                            bounds.x = 0;
                        } else if (bounds.x + bounds.width > parent.getWidth()) {
                            bounds.x = parent.getWidth() - bounds.width;
                        }
                        if (bounds.y < 0) {
                            bounds.y = 0;
                        } else if (bounds.y + bounds.height > parent.getHeight()) {
                            bounds.y = parent.getHeight() - bounds.height;
                        }
    
                        mobby.setBounds(bounds);
    
                    }
                });
                moveTimer.setInitialDelay(0);
    
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 400);
            }
    
            public class ChangeHandler implements ChangeListener {
    
                private Direction direction;
    
                public ChangeHandler(Direction direction) {
                    this.direction = direction;
                }
    
                @Override
                public void stateChanged(ChangeEvent e) {
                    ButtonModel b = (ButtonModel) e.getSource();
                    if (b.isPressed()) {
                        moveDirection = direction;
                        moveTimer.start();
                    } else {
                        moveTimer.stop();
                    }
                }
    
            }
        }
    
    }
    

    你可能想通读Concurrency in Swing了解更多细节

    根据OP的输入进行更新

    令人惊讶的是,使用按键代替按键也是同样的方法。你有一个开始动作和一个结束动作,你只需要弄清楚如何应用这些状态

    强烈建议您在KeyListener上使用Key Bindings。主要原因是KeyListener存在焦点问题,密钥绑定API有能力克服或控制这些问题

    基本前提是,您希望在按键和按键释放时注册按键操作。使用密钥绑定API可以相对容易地实现这一点

    注意事项:这个例子一次只允许一个方向。例如,如果您按下向上向下,向下操作将获胜。这是因为我使用了enum作为方向。您可以通过使用xDeltayDelta值来轻松更改此设置,这将允许您同时修改垂直和水平方向。。。但不能为你做一切;)

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Point;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import java.awt.event.KeyEvent;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import javax.swing.AbstractAction;
    import javax.swing.ActionMap;
    import javax.swing.ButtonModel;
    import javax.swing.InputMap;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.KeyStroke;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    
    public class MovePane {
    
        public static void main(String[] args) {
            new MovePane();
        }
    
        public MovePane() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public enum Direction {
    
            None, Up, Down, Left, Right;
        }
    
        public class TestPane extends JPanel {
    
            private JPanel mobby;
            private Timer moveTimer;
            private Direction moveDirection = Direction.None;
    
            public TestPane() {
                mobby = new JPanel();
                mobby.setBackground(Color.RED);
                mobby.setSize(50, 50);;
                setLayout(new BorderLayout());
                JPanel pool = new JPanel(null);
                pool.add(mobby);
                add(pool);
    
                moveTimer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Container parent = mobby.getParent();
                        Rectangle bounds = mobby.getBounds();
                        switch (moveDirection) {
                            case Up:
                                bounds.y ;
                                break;
                            case Down:
                                bounds.y++;
                                break;
                            case Left:
                                bounds.x ;
                                break;
                            case Right:
                                bounds.x++;
                                break;
                        }
    
                        if (bounds.x < 0) {
                            bounds.x = 0;
                        } else if (bounds.x + bounds.width > parent.getWidth()) {
                            bounds.x = parent.getWidth() - bounds.width;
                        }
                        if (bounds.y < 0) {
                            bounds.y = 0;
                        } else if (bounds.y + bounds.height > parent.getHeight()) {
                            bounds.y = parent.getHeight() - bounds.height;
                        }
    
                        mobby.setBounds(bounds);
    
                    }
                });
                moveTimer.setInitialDelay(0);
                InputMap im = pool.getInputMap(WHEN_IN_FOCUSED_WINDOW);
                ActionMap am = pool.getActionMap();
    
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "UpPressed");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "UpReleased");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "DownPressed");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "DownReleased");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "LeftPressed");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "LeftReleased");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "RightPressed");
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "RightReleased");
    
                KeyUpAction keyUpAction = new KeyUpAction();
                am.put("UpReleased", keyUpAction);
                am.put("DownReleased", keyUpAction);
                am.put("LeftReleased", keyUpAction);
                am.put("RightReleased", keyUpAction);
    
                am.put("UpPressed", new MoveAction(Direction.Up));
                am.put("DownPressed", new MoveAction(Direction.Down));
                am.put("LeftPressed", new MoveAction(Direction.Left));
                am.put("RightPressed", new MoveAction(Direction.Right));
    
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(400, 400);
            }
    
            public class KeyUpAction extends AbstractAction {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    moveTimer.stop();
                    moveDirection = Direction.None;
                }
            }
    
            public class MoveAction extends AbstractAction {
    
                private Direction direction;
    
                public MoveAction(Direction direction) {
                    this.direction = direction;
                }
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    moveDirection = direction;
                    moveTimer.start();
                }
            }
        }
    }
    
  3. # 3 楼答案

    使用^{}移动面板,将mouseListener添加到面板,并覆盖mousePressedmouseReleased方法


    更新:

    评论如下:

    The OP said I want to move the panel with Keyboard buttons.

    你在问题中没有提到键盘,你只是说按钮,不管怎样,这本教程对你现在和将来都有帮助

    如果您有问题,请回来,我将发布一个移动面板的示例,但现在,我不会发布它,因为我相信您不会阅读教程,您只需复制我的示例,然后离开阅读图茨