您需要考虑许多重要的考虑因素.
>按钮并非按这种方式工作.它们被设计为在单击(按下和释放)时触发和动作事件,因此您不能使用常规的动作API.对我们来说幸运的是,还有其他方法可以确定按钮的状态.本示例在ButtonModel上使用ChangeListener并根据模型的状态执行操作.
>组件通常在布局管理器的控制下.这意味着为了能够移动组件,我们需要将其关闭(也称为空布局或绝对布局).通常,我不建议这样做,但这是唯一可行的方法.然而.删除布局管理器后,您有责任确保正确放置组件并调整其大小……这不能掉以轻心.您想要实现的目标的更多上下文将产生更好的答案
>当按钮被“按下”时,我们需要一种方法来确定移动组件的方法.本示例使用一个简单的枚举来确定移动组件的方向.您可以轻松地使用x / yDelta并直接修改组件的x / y位置.两者都应该工作正常.
> Swing是一个单线程环境.也就是说,对UI的所有交互和修改都应在事件调度线程的上下文中执行.但是,任何阻止EDT的操作都将阻止UI开始更新或阻止任何新事件开始处理.这意味着,为了移动组件,我们不能简单地使用while循环,因为它永远不会结束(不会处理任何新事件).相反,此示例使用javax.swing.Timer,它在后台等待并在EDT上下文中的每个刻度上引发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();
}
}
}
}
}
根据OP的输入进行了更新
令人惊讶的是,使用按键而不是按钮.您有一个开始操作和一个结束操作,您只需要弄清楚如何应用这些状态.
强烈建议您在KeyListener上使用Key Bindings.主要原因是KeyListener遭受焦点问题困扰,键绑定API具有克服或控制焦点的能力.
基本前提是,您要在按键和释放键上注册一个按键动作.使用键绑定API相对容易实现.
警告:此示例一次只允许一个方向.例如,如果按“向上”和“向下”,则向下操作将获胜.这是因为我正在使用枚举作为方向.您可以改为使用xDelta和yDelta值来轻松更改此设置,这将允许您同时修改垂直和水平方向…但是不能为您做任何事情;)
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();
}
}
}
}