如何使用java中的键移动矩形 [英] How to move a rectangle using keys in java
问题描述
我一直试图找出如何使用箭头键移动矩形,但似乎有问题。
我使用 KeyListener
检测所有关键输入。
我不知道如何使用KeyBinding因此我不希望解决方案有它。
我是计划在掌握KeyListener之后立即学习它。请给我关于如何解决它的建议。
I have been trying to find out how to move a rectangle with the arrow keys but there seems to be a problem.
I am using a KeyListener
to detect all of the key inputs.
I do not know how to use a KeyBinding therefore I do not wish for the solution to have it.
I am planning to learn it right after mastering KeyListener. Please give me suggestions on how to fix it.
package expo;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Expo extends JPanel implements KeyListener{
int x = 0;
int y = 0;
@Override
public void keyTyped(KeyEvent e) {
//System.out.println("Key Typed");
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_DOWN){
System.out.println("Key Pressed" + e.getKeyCode());
y = y + 2;
}
}
@Override
public void keyReleased(KeyEvent e) {
//System.out.println("Key Released");
}
public void paint(Graphics g){
g.setColor(Color.BLUE);
g.drawRect(x ,y,100,100);
repaint();
}
public static void main(String[] args) throws InterruptedException {
Expo expo = new Expo();
JFrame f = new JFrame();
f.setVisible(true);
f.setSize(500,500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addKeyListener(expo);
f.add(expo);
f.repaint();
}
}
推荐答案
- 在
KeyListener
上使用键绑定API,它解决了KeyListener
遭受的焦点相关问题。 如何使用密钥绑定 - 不要破坏油漆链。如果覆盖其中一个
paint
方法,则必须调用它的super
实现。 - 避免重写
paint
,它通常在绘制过程中处于高位,并且由于绘画的工作方式,在绘制子组件时并不总是被调用,会引起一些有趣的问题。 Convention建议改为使用paintComponent
。请参阅在AWT和Swing中绘画和执行自定义绘画以获取更多详细信息 - 尝试调用
JFrame #setVisible
最后,在您建立用户界面之后,您会发现它会导致更少的问题
- Use the key bindings API over
KeyListener
, it solves the focus related issues thatKeyListener
suffers from. How to Use Key Bindings - Don't break the paint chain. If you override one of the
paint
methods, you must call it'ssuper
implementation. - Avoid overriding
paint
, it's normally to high in the paint process and because of the way painting works, doesn't always get called when a child component is painted, which can cause some interesting issues. Convention recommends usingpaintComponent
instead. See Painting in AWT and Swing and Performing Custom Painting for more details - Try calling
JFrame#setVisible
last, after you have established the UI, you will find it causes less issues
作为一个例子...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Expo extends JPanel {
int x = 0;
int y = 0;
public Expo() {
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
y += 2;
if (y + 100 > getHeight()) {
y = getHeight() - 100;
}
repaint();
}
});
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
y -= 2;
if (y < 0) {
y = 0;
}
repaint();
}
});
}
public void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(condition);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(x, y, 100, 100);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public static void main(String[] args) throws InterruptedException {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Expo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
这一切都很酷,一切都很好,但是现在,当你按住键时,矩形会移动,暂停,然后开始稳定地移动!?
That's all cool and everything, but now, when you hold down the key, the rectangle moves, pauses and then begins to move steadily!?
这实际上很正常。相反,你可以做的是建立一个更新循环,它不断监视一组标志的状态,决定在设置这些标志时要做什么并更新UI。
This is actually quite normal. Instead, what you can do, is establish an "update loop" which constantly monitors the state of a set of flags, makes decisions about what to do when those flags are set and updates the UI.
那么,这样做,是设置一个Swing Timer
,它每40毫秒滴答一次,检查当前垂直键状态的状态,更新相应的 y
位置并安排重绘
,这样可以让我们更加顺畅,因为我们不依赖于重复键击。
So, what this does, is sets up a Swing Timer
which ticks every 40 milliseconds, checks the state of the current "vertical key state", updates the y
position accordingly and schedules a repaint
, this allows for a much more smoother movement as we're not reliant on the repeating key stroke.
这也证明了键绑定API的强大功能,因为它建立了一个 Action
处理向上和向下移动以及相关的密钥释放...整洁
This also demonstrates the power of the key bindings API, as it establishes a single Action
to handle both the up and down movements and the associated key releases...neat
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Expo extends JPanel {
int x = 0;
int y = 0;
public enum VerticalKey {
UP, DOWN, NONE;
}
public enum HorizontalKey {
LEFT, RIGHT, NONE;
}
private VerticalKey verticalKeyState = VerticalKey.NONE;
private HorizontalKey horizontalKeyState = HorizontalKey.NONE;
public Expo() {
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new VerticalAction(VerticalKey.DOWN));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.down", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), new VerticalAction(VerticalKey.NONE));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "pressed.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new VerticalAction(VerticalKey.UP));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "released.up", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), new VerticalAction(VerticalKey.NONE));
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switch (verticalKeyState) {
case UP:
y -= 2;
break;
case DOWN:
y += 2;
break;
}
if (y + 100 > getHeight()) {
y = getHeight() - 100;
} else if (y < 0) {
y = 0;
}
repaint();
}
});
timer.start();
}
public void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(condition);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(x, y, 100, 100);
}
public void setVerticalKeyState(VerticalKey verticalKeyState) {
this.verticalKeyState = verticalKeyState;
System.out.println(verticalKeyState);
}
public void setHorizontalKeyState(HorizontalKey horizontalKeyState) {
this.horizontalKeyState = horizontalKeyState;
}
public class VerticalAction extends AbstractAction {
private VerticalKey verticalKey;
public VerticalAction(VerticalKey verticalKeys) {
this.verticalKey = verticalKeys;
}
@Override
public void actionPerformed(ActionEvent e) {
setVerticalKeyState(verticalKey);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public static void main(String[] args) throws InterruptedException {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Expo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
这篇关于如何使用java中的键移动矩形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!