如何将焦点切换到画布?

时间:2014-08-10 08:55:39

标签: java swing focus

我有这个课,我希望在调用它之后立即将焦点切换到Game类。我可能不理解焦点的目的但是当我按下开始时我必须点击游戏画布本身以便我可以使用键盘。换句话说:我怎样才能这样做,所以我不必点击它来使用键盘?

package com.runner.panels;

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;

import com.runner.main.Game;
import com.runner.main.Main;

public class PlayPanel extends JPanel{

    private static final long serialVersionUID = 1L;

    public PlayPanel(){
        //setting the layout of the playpanel to null
        setLayout(null);

        //setting up the info panel : high score, meters ran, pause button etc...
        JPanel info = new JPanel();
        info.setBounds(0,0,1200,50);
        add(info);

        //back button
        JButton back = new JButton("Back");
        info.add(back);

        Game game = new Game();
        game.setBounds(0,50,1200,521);
        game.setBackground(Color.black);
        add(game);

        back.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                CardLayout cl = (CardLayout) Main.mainp.getLayout();
                cl.show(Main.mainp, "Menu");
            }
        });
    }
}

3 个答案:

答案 0 :(得分:1)

偏离主题:(有点)

您正在进行Main.mainp.getLayout();这一事实,静态调用该面板会告诉我您的设计很差,应该查看其他选项,例如Model-view-controller patternObserver pattern,或者至少将Main的引用传递给面板,而不是使用静态对象/调用。

返回主题

听起来像是常见的KeyListener问题。通常,为了获得焦点,请致电requestFocusInWindow()。但是你仍然不得不担心其他组件会在事后发现重点。

我建议使用Key Bindings而不是KeyListener。您可以更好地控制焦点。例如,通过使用

InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("SPACE"), "hitSpace");
panel.getActionMap().put("hitSpace", new AbstractAction(){
    public void actionPerformed(ActionEvent e) {
        // do something.
    }
});

一旦您从CardLayout显示操作,该面板就可以立即访问该操作。如果您碰巧使用任何其他可能会将焦点从面板中移开的组件,由于WHEN_IN_FOCUSED_WINDOW输入映射

,仍然可以访问该操作

这是一个简单的例子。如果它在面板A上,则输入A,您将看到它打印。如果您键入B,它将无法打印,因为面板A在窗口中。此外,如果您尝试按下面板中的按钮以窃取焦点,您仍然可以键入并仍然可以打印。面板B也是如此

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class Main {

    CardLayout layout = new CardLayout();
    JPanel panel = new JPanel(layout);
    JPanel p1 = new JPanel() {
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    };
    JPanel p2 = new JPanel() {
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    };
    JButton b1 = new JButton("panelA");
    JButton b2 = new JButton("panelB");

    public Main() {
        addKeyBind(p1, "pressA", "A");
        addKeyBind(p2, "pressB", "B");
        p1.add(new JButton("Button for Panel A"));
        p2.add(new JButton("Button for Panel B"));

        panel.add(p1, "panelA");
        panel.add(p2, "panelB");

        b1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                show("panelA");
            }
        });
        b2.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                show("panelB");
            }
        });
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(b1);
        buttonPanel.add(b2);

        JFrame frame = new JFrame();
        frame.add(panel);
        frame.add(buttonPanel, BorderLayout.PAGE_END);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void show(String panelName) {
        layout.show(panel, panelName);
    }

    private void addKeyBind(JComponent comp, String name, final String stroke) {
        InputMap im = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        im.put(KeyStroke.getKeyStroke(stroke), name);
        comp.getActionMap().put(name, new AbstractAction(){
            public void actionPerformed(ActionEvent e) {
                System.out.println(stroke + " pressed");
            }
        });
    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new Main();
            }
        });
    }
}

请花一些时间浏览我为您提供的Key Bindings链接以了解更多信息。

返回主题

看看@AndrewThompson关于null布局的评论。了解how to use the LayoutManagers

答案 1 :(得分:0)

我相信如果添加

,您的问题就会得到解决
setFocusable(true);

到你的PlayPanel构造函数(适合我)。 此外,如果您希望GUI中的特定Panel在启动应用程序时具有焦点,请按照“user3218114”注释中的链接进行操作,因为这将说明如何使用Listener实现此功能。

祝你好运!

答案 2 :(得分:0)

你不需要做任何事情。容器应该是可以专注的。
这是一个演示代码。

包一;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;

public class PlayPanel extends Canvas {

    public static void main(String... args) {
        PlayPanel p = new PlayPanel();
        p.addFocusListener(new FocusListener() {

            @Override
            public void focusGained(FocusEvent e) {
                p.msg = "Focus gained";
                p.repaint();
            }

            @Override
            public void focusLost(FocusEvent e) {
                p.msg = "Focus Lost";
                p.repaint();
            }
        });

        p.setBackground(Color.GRAY);
        JFrame f = new JFrame();
        f.add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(300, 200);
        f.setLocation(300, 300);
        f.setVisible(true);
    }

    String msg = "NO FOCUS";

    public void paint(Graphics g) {
        g.drawString(msg, 50, 50);
    }
}