- 使用密鑰綁定API而不是
KeyListener
,它解決了KeyListener
遭受的焦點相關問題。 How to Use Key Bindings
- 不要破壞塗料鏈。如果您重寫
paint
方法之一,則必須將其稱爲super
實現。
- 避免重寫
paint
,它通常在繪畫過程中很高,並且由於繪畫工作的方式,在繪製子組件時並不總是被調用,這可能會導致一些有趣的問題。公約建議改用paintComponent
。見Painting in AWT and Swing和Performing Custom Painting更多細節
- 嘗試調用
JFrame#setVisible
最後,你已經建立了UI之後,你會發現它會導致更少的問題
舉個例子...
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);
}
});
}
}
這一切酷酷的一切,但現在,當你按下鍵時,矩形移動,暫停,然後開始穩步移動!?
這實際上很正常。相反,你可以做的是建立一個「更新循環」,它不斷監視一組標誌的狀態,決定在設置這些標誌並更新UI時該怎麼做。
那麼,這是什麼呢,是建立一個Swing Timer
其中蜱每40毫秒,檢查當前的「垂直化國家重點」的狀態,相應地更新y
位置與日程安排repaint
,這使得一個更因爲我們不依賴於重複擊鍵,所以運動更流暢。
這也表明了鍵綁定API的權力,因爲它建立了一個單一的Action
處理上下運動和相關聯的鍵將同時釋放...整齊
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);
}
});
}
}
1)覆蓋'paintComponent' ,而不是'paint' 2)不要在paint(或paintComponent)中調用'repaint' 3)如果你想在'KeyListener.keyPressed'被觸發後重新繪製,然後調用repaint。 4)如果KeyListener未觸發,請確保包含偵聽器的組件在焦點 – copeg
在矩形重畫時重繪,它在原始焦點上重繪 – yj2000
也嘗試了paintcomponent,但不會顯示矩形 – yj2000