Java按住按钮时移动对象 [英] Java Making objects move while buttons held

查看:102
本文介绍了Java按住按钮时移动对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How do I make a JPanel move while a button is held down and stop when the button is released. I have tried using thread.start() with a Runnable and ways like that. I always run in to errors. Can anyone help me though?

推荐答案

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

There are a number of important considerations that you need to take into consideration.


  1. 按钮的设计不是这样的。它们被设计为在单击(按下并释放)时触发和操作事件,因此您无法使用常规操作API。幸运的是,还有其他方法可以确定按钮的状态。此示例在 ButtonModel 上使用 ChangeListener ,并根据模型的状态执行操作。

  2. 组件通常在布局管理器的控制之下。这意味着为了能够移动组件,我们需要关闭它(也称为 null 绝对布局)。通常,我会劝阻这一点,但这是唯一可行的方法。然而。删除布局管理器后,您将负责确保组件的位置和尺寸正确...这不是一件轻松的工作。更多关于你想要实现的内容会产生更好的答案

  3. 当按下按钮时,我们需要一种方法来确定移动组件的方法。此示例使用简单的枚举来确定移动组件的方向。您可以轻松使用 x / yDelta 并直接修改组件 x / y 位置。两者都应该正常工作。

  4. Swing是一个单线程环境。也就是说,期望在UI事件调度线程的上下文中执行对UI的所有交互和修改。但是阻止EDT的任何操作都将阻止UI开始更新或开始处理任何新事件。这意味着,为了移动组件,我们不能简单地使用 while-loop ,因为它永远不会结束(不会处理新事件)。相反,此示例使用 javax.swing.Timer ,它在后台等待并在每个tick上引发 ActionEvent 在EDT的背景下。发生勾号,我们修改面板的位置

  1. Buttons aren't designed to work this way. They are designed to trigger and action event when they are clicked (pressed and released), so you can't use the normal action API. Lucky for us, there are other ways to determine the state of buttons. This example uses a ChangeListener on the ButtonModel and takes actions based on the state of the model.
  2. Components are normally under the control of layout managers. This means in order to be able to move the component, we need to turn this off (also known as null or absolute layouts). Normally, I would discourage this, but this is the only way this will work. However. Once you remove the layout manager, you become responsible for ensuring the component(s) are properly positioned and sized...this is not work to be taken lightly. More context of what you're trying to achieve would produce better answers
  3. While the button is "pressed", we need a way to determine which way to move the component. This example uses a simple enum to determine which direction to move the component. You could just as easily use a x/yDelta and modify the components x/y position directly. Either should work fine.
  4. Swing is a single thread environment. That is, all interactions and modifications to the UI are expected to be executed within the context of the Event Dispatching Thread. But any actions that block the EDT will prevent the UI from begin update or any new events from begin processed. This means, in order to move the component, we can't simply use a while-loop, because it will never end (no new events will be processed). Instead, this example uses a javax.swing.Timer, which waits in the background and raises an ActionEvent on each tick within the context of the EDT. The a tick occurs, we modify the location of the panel

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();
                }
            }

        }
    }

}

您可能希望通读 Swing中的并发以获取更多详细信息......

You might like to have a read through Concurrency in Swing for more details...

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

Use key strokes instead of buttons is surprisingly the same approach. You have a start action and a end action, you just need to figure out how to apply those states.

强烈建议你使用键绑定超过 KeyListener 。主要原因是 KeyListener 受到焦点问题的影响,密钥绑定API有能力过度控制。

It is highly recommended that you use Key Bindings over KeyListener. The main reason is KeyListener suffers from focus issues, which the key bindings API has the ability to over come or control.

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

The basic premise is, you want to register a key action on key press and key release. This is relatively easy to accomplish with the key bindings API.

警告:此示例一次只允许单个方向。如果按,例如 Up Down ,则向下操作将胜出。这是因为我使用枚举作为方向。您可以使用 xDelta yDelta 值轻松更改此值,这样您就可以修改纵向和横向同时指示...但不能为你做所有事情;)

Caveat: This example will only allow for a single direction at a time. If you press, for example, Up and Down, the down action will win out. This is because I'm using a enum for the direction. You can easily change this by using a xDelta and yDelta value instead, which would allow you to modify the vertical and horizontal directions simultaneously...but can't do everything for you ;)

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();
            }
        }
    }
}

这篇关于Java按住按钮时移动对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆