我正在嘗試用 Java 為游戲開發一個主選單,但我的JMenuItems 不會聽KeyEvents 并且我不明白為什么。請注意,我不想設定任何JMenuBars 或JMenus,因為該程式旨在成為與螢屏閱讀器一起使用的游戲,因此我不希望讀取可訪問性角色。此外,添加選單會使使用鍵盤訪問元素變得復雜,我希望焦點從第一個選項開始。
這是我的代碼:
import java.util.Set;
import java.util.HashSet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.MenuKeyEvent;
import javax.swing.event.MenuKeyListener;
public class Screen {
public Screen() {
// Accept arrow keys as focus traversal keys
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTrave rsalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,set);
// definition of Menu Items
JMenuItem mi=new JMenuItem("play");
JMenuItem mi2=new JMenuItem("exit");
mi.setFocusable(true);
mi2.setFocusable(true);
// Attempt with MenuKeyListener
mi.addMenuKeyListener(new MenuKeyListener() {
public void menuKeyReleased(MenuKeyEvent e) {
System.out.println("Play released");
}
public void menuKeyTyped(MenuKeyEvent e) {}
public void menuKeyPressed(MenuKeyEvent e) {}
});
// Attempt with ActionListener
mi2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
mi.setVisible(true);
mi2.setVisible(true);
JPanel mp = new JPanel();
JFrame mf = new JFrame("Game");
mf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mp.add(mi);
mp.add(mi2);
mf.add(mp);
mf.setVisible(true);
}
public static void main(String args[]) {
new Screen();
}
}
我已經嘗試使用ActionListenerand MenuKeyListener,有和沒有JPanel,不斷變化的可見性......我也嘗試過使用,KeyEventDispatcher但我不知道如何將 a 發送KeyEvent到回傳的組件KeyboardFocusManager.getFocusOwner()。
請幫忙。
uj5u.com熱心網友回復:
在這種情況下有很多幫助。對于初學者,
public static void main(String args[]) {
new Screen();
}
是錯的。在主執行緒上執行任何改變 Swing 布局或呈現的操作是不合適的。而是做
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Screen();
}
});
}
如果您決定以這種方式將 Swing 呼叫放入物件的建構式中。
理想情況下,您Screen將是一款JFrame專為滿足您的需求而定制的產品。這意味著您可能想要創建一個GamePanel擴展的新類JPanel
public class Screen extends JFrame {
public Screen() {
super("Game"); // to remind us that the JFrame is created
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new GamePanel());
pack();
setVisible(true);
}
}
public class GamePanel extends JPanel {
public GamePanel() {
super();
}
}
現在,如果您希望該面板監聽按鍵,則需要添加一個KeyListener介面。這只賦予它聆聽的能力,并沒有讓它聆聽。
public class GamePanel extends JPanel implements KeyListener {
...
public void keyTyped(KeyEvent e) {
System.out.println("KEY TYPED: " e);
}
public void keyPressed(KeyEvent e) {
System.out.println("KEY PRESSED: " e);
}
public void keyReleased(KeyEvent e) {
System.out.println("KEY RELEASED: " e);
}
}
現在您可以將您的關鍵偵聽器添加到Screen或添加到GamePanel(它會自己偵聽)。每當焦點在這些專案之一上,并且按下一個鍵時,偶數將被路由到偵聽器。
public class GamePanel extends JPanel implements KeyListener {
public GamePanel() {
super();
addKeyListener(this);
}
...
}
理想情況下,您可能不希望將您的鍵偵聽器與面板本身結合起來,而是使其成為某種“命令處理器”。在這種情況下,KeyListener從 中洗掉代碼JPanel并創建一個CommmandHandler實作 的全新物件KeyListener。
就目前而言Actions,它們是方便的專案,可以預先配置有很多東西(圖示、加速鍵、文本、回呼函式)的選單條目。如果您出于某種原因避免使用選單,您會發現它們在設定選單方面的大部分效用都被誤導了。實際上,它們是配置MenuItem物件以處理鍵的配置條目(通過KeyListener介面然后調度擺動Event物件。這通過應用程式提供“比鍵更好”的專案跟蹤,因為它將鍵盤字母轉換為傳遞k的類ActionEvent到注冊的“動作處理程式”通常是AbstractAction.
一個動作的例子是
public class MoveLeft extends AbstractAction { // which extends ActionListener
private final GameState gameState;
public MoveLeft(GameState gameState) {
super("move left", new ImageIcon(MoveLeft.class.getResource("/images/moveleft.png"));
putValue("SHORT_DESCRIPTION", "left");
putValue("MNEMONIC_KEY", "l");
this.gameState = gameState;
}
public void actionPerformed(ActionEvent e) {
gamestate.getSelected().moveLeft();
}
}
假設你想要這種便利,你可以CommandHandler用Actions初始化你的,也許像這樣:
public CommandHandler implements KeyListener {
private int actionId;
...
public void addAction(Action action) {
handlers.put(action.getValue("MNEMONIC_KEY")., action);
}
public void keyTyped(KeyEvent e) {
Action action = handlers.get(String.valueOf(e.getKeyChar());
ActionEvent event = new ActionEvent(this, id, action.getValue("NAME"));
action.actionPerformed( event );
}
}
如您所見,Action為游戲中的動作定義 s的額外便利是通過使使用它們的組件由它們配置(并在KeyListener實作中使用它們)來平衡的。
對于大型專案,列出所有操作的簡單性通常使創建操作非常值得;但是,對于主要使用自定義組件的較小專案,使KeyListener組件使用操作所增加的一次性成本可能會超過收益。
uj5u.com熱心網友回復:
不要這樣使用JMenuItem,這不是它的用途
相反,我會從JButton. 以下使用您的焦點橫向代碼、ActionAPI和鍵系結 API
import java.awt.AWTKeyStroke;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
Set<AWTKeyStroke> set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("DOWN"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set);
set = new HashSet<AWTKeyStroke>(KeyboardFocusManager.getCurrentKeyboardFocusManager().getDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
set.add(KeyStroke.getKeyStroke("UP"));
KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, set);
Action playAction = new AbstractAction("Play") {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("play");
}
};
playAction.putValue(Action.MNEMONIC_KEY, (int)'P');
Action exitAction = new AbstractAction("Exit") {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("exit");
}
};
exitAction.putValue(Action.MNEMONIC_KEY, (int)'x');
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0), "play");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, 0), "exit");
am.put("play", playAction);
am.put("exit", exitAction);
JButton playButton = new JButton(playAction);
JButton exitButton = new JButton(exitAction);
add(playButton, gbc);
add(exitButton, gbc);
}
}
}
現在,您可以使用JLabel,但是,JLabel默認情況下不可聚焦,也不呈現任何型別的焦點指示。相反,我可能會想把 a 去掉,JButton這樣它就不會繪制它的邊框或內容/背景
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/374376.html
