Java使对象在按钮保持时移动

时间:2013-08-13 21:50:05

标签: java multithreading swing jframe jcomponent

如何在按住按钮时进行JPanel移动,并在释放按钮时停止。我尝试过使用带有Runnable的thread.start()和类似的方法。我总是遇到错误。有人可以帮助我吗?

3 个答案:

答案 0 :(得分:2)

您需要考虑许多重要因素。

  1. 按钮的设计不是这样的。它们被设计为在单击(按下并释放)时触发和操作事件,因此您无法使用常规操作API。幸运的是,还有其他方法可以确定按钮的状态。此示例在ChangeListener上使用ButtonModel,并根据模型的状态执行操作。
  2. 组件通常在布局管理器的控制之下。这意味着为了能够移动组件,我们需要将其关闭(也称为nullabsolute布局)。通常,我会劝阻这一点,但这是唯一可行的方法。然而。删除布局管理器后,您将负责确保组件的正确定位和尺寸......这不是一件轻松的工作。更多关于你想要达到的目标会产生更好的答案
  3. 按下“按下”按钮时,我们需要一种方法来确定移动组件的方式。此示例使用简单的enum来确定移动组件的方向。您可以轻松使用x/yDelta并直接修改组件x/y位置。要么工作正常。
  4. Swing是一个单线程环境。也就是说,期望在UI事件调度线程的上下文中执行对UI的所有交互和修改。但是阻止EDT的任何操作都将阻止UI开始更新或开始处理任何新事件。这意味着,为了移动组件,我们不能简单地使用while-loop,因为它永远不会结束(不会处理新事件)。相反,此示例使用javax.swing.Timer,它在后台等待并在EDT上下文中的每个刻度上引发ActionEvent。发生勾号,我们修改面板的位置
  5. 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

    的输入进行了更新

    使用击键而不是按钮令人惊讶地采用相同的方法。你有一个开始动作和一个结束动作,你只需要弄清楚如何应用这些状态。

    强烈建议您使用Key Bindings而不是KeyListener。主要原因是KeyListener受到焦点问题的困扰,密钥绑定API有能力过度控制。

    基本前提是,您希望在按键和按键释放时注册关键动作。使用密钥绑定API相对容易实现。

    警告:此示例一次只允许单个方向。如果按,例如 Up Down ,则向下操作将胜出。这是因为我使用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();
                }
            }
        }
    }
    

答案 1 :(得分:0)

使用SwingTimer移动面板并将mouseListener添加到面板并覆盖mousePressedmouseReleased方法。


UPDATE:

来自评论:

  

OP说我想用 Keyboard buttons 移动面板。

你在问题​​中没有提到键盘,你只是说按钮,无论如何,在How to use Key Bindings上学习本教程,它会帮助你现在和将来。

如果您有问题,请回来,我会发布移动面板的示例,但是现在,我没有发布它,因为我确定您不会阅读教程,您只需复制我的示例离开读书。

答案 2 :(得分:-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和mouseRelaesed方法中调用start()stop()方法。