背景
我有一个简单的游戏。我有一个JPanel
课,每个东西都有(菜单,游戏,游戏结束)。
然后我决定,我应该让我的游戏更好,我制作了两个面板(一个用于菜单,第二个用于游戏lvls)。
每件事都很好,但我的KeyAdapter
课程不适用于JPanel
。我不知道为什么它不想集中注意力。
我有我的:
扩展JFrame
的主要类,此处我将面板(和KeyListener
添加到第一个面板)
public class JavaGame2 extends JFrame {
public JavaGame2(){
gamePanel = new GamePanel();
menuPanel = new MenuPanel();
setContentPane(menuPanel);
menuPanel.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
menuPanel.changeCursor();
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
menuPanel.changeCursor();
}
if (menuPanel.getCursorPos()==1){
if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
setContentPane(gamePanel);
//add(gamePanel);
}
}
else{
if ((e.getKeyCode() == KeyEvent.VK_ENTER)) {
System.exit(0);
}
}
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
setTitle("JavaGame2");
setResizable(false);
}
public static void main(String[] args) {
JFrame jgame = new JavaGame2();
jgame.setVisible(true);
}
}
MenuPanel
类扩展JPanel
public class MenuPanel extends JPanel implements ActionListener{
public MenuPanel(){
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
setSize(800,600);
}
public void actionPerformed(ActionEvent e) {
}
}
此处GamePanel
类
public class GamePanel extends JPanel implements ActionListener{
public GamePanel (){
addKeyListener(new GameAdapter());
setFocusable(true);
requestFocus();
setBackground(Color.BLACK);
setDoubleBuffered(true);
setSize(800,600);
}
private class GameAdapter extends KeyAdapter{
public void keyReleased(KeyEvent e) {
ship.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
ship.keyPressed(e);
}
}
}
它不起作用。 GamePanel
我不想专注,我试着去做我读过的每一件事。
我想你会说JPanel
不是可集中的组成部分。但当有一个小组时,它在某种程度上有效。
如何解决此焦点问题?
也许你会说你更喜欢不使用KeyAdapter
,但我觉得它在我的代码中看起来很不错。
setFocusable()
?还是requestFocus()
? requestFocusInWindow()
?我应该如何使用它们?也许我之前有过错,这不是我的第一个问题?
提前致谢。
感谢您的编辑。
答案 0 :(得分:3)
简短回答,使用key bindings API,它允许您在触发关键事件之前控制组件所需的焦点水平。
更长的答案,活动面板需要具有键盘焦点。您可以使用requestFocusInWindow
,但无法保证组件实际上会获得焦点。什么时候打电话这是件棘手的事。您可以尝试覆盖addNotify
面板并打电话到那里,只要确保先拨打super.addNotify
,否则就会发生奇怪的事情
如果组件失去焦点,您还需要考虑会发生什么
作为旁注:
setDoubleBuffered(true);
无关紧要,因为默认情况下Swing组件是双缓冲的。通常,如果要打印组件,可以禁用此功能。通过调用它没有坏处setSize
是无关紧要的,因为组件将在布局管理器的控制下,这将决定组件本身的大小。您最好覆盖getPreferredSize
并为布局管理器返回适当的大小setSize
上拨打JFrame
也是一个坏主意。框架具有边框,这意味着您的可视区域将是frame size - the frames border insets
,这将小于您指定的800x600。最好使用之前的评论,并在pack
上调用JFrame
,这会在内容周围打包框架,以满足内容要求...... KeyListener
本地化为实际组件本身,这样可以让组件充当它自己的控制器,使其更具可移植性......恕我直言更新了控制器构思......
A"真的"简化的概念是拥有某种"控制器"菜单和游戏面板可以通过,例如...
进行通信public interface GameController {
public void showMenu();
public void showGame();
}
然后,您可以将此界面的引用传递给MenuPanel
...
public class MenuPanel extends JPanel implements ActionListener{
public MenuPanel(GameController controller){
//...
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
GamePanel
...
public class GamePanel extends JPanel implements ActionListener{
public GamePanel (GameController controller){
//...
}
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
显然,您需要构建控制器的实现...
public class CardLayoutGameController implements GameController {
public static final String GAME_PANEL = "GamePanel";
public static final String MENU_PANEL = "MenuPanel";
private Container container;
private CardLayout cardLayout;
public CardLayoutGameController(Container parent, CardLayout layout) {
container = parent;
cardLayout = layout;
}
public void showMenu() {
cardLayout.show(container, MENU_PANEL);
}
public void showGame() {
cardLayout.show(container, GAME_PANEL);
}
}
然后,您将围绕此控制器构建UI,例如......
public class JavaGame2 extends JFrame {
public JavaGame2(){
CardLayout layout = new CardLayout();
setLayout(layout);
GameController controller = new CardLayoutGameController(getContentPane(), layout);
gamePanel = new GamePanel(controller);
menuPanel = new MenuPanel(controller);
add(gamePanel, CardLayoutGameController.GAME_PANEL);
add(menuPanel, CardLayoutGameController.MENU_PANEL);
controller.showMenu();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setTitle("JavaGame2");
setResizable(false);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame jgame = new JavaGame2();
jgame.setVisible(true);
}
});
}
}
这只是一个"例子"为了激发这个想法,我们没有对此进行过测试,只是在这里被黑了,所以它可能会爆炸:P