Java按住按钮时移动对象

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

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

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

在此处输入图像描述

 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中的Concurrency以获取更多详细信息……

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

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


更新:

来自评论:

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

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

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

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

有一个包含的类

 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()方法。