【问题标题】:How can I switch focus to a canvas?如何将焦点切换到画布?
【发布时间】:2014-08-10 08:55:39
【问题描述】:

我有这个类,我想在调用它后立即将焦点切换到 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");
            }
        });
    }
}

【问题讨论】:

标签: java swing focus


【解决方案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 对空布局的评论。学习how to use the LayoutManagers

【讨论】:

    【解决方案2】:

    我相信如果你添加,你的问题会得到解决

    setFocusable(true);
    

    到您的 PlayPanel 构造函数(对我有用)。 此外,如果您希望 GUI 中的特定面板在您启动应用程序时具有焦点,请点击“user3218114”评论中的链接,因为这将解释如何使用侦听器实现此功能。

    祝你好运!

    【讨论】:

      【解决方案3】:

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

      包装一;

      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);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-07-09
        • 1970-01-01
        • 2018-05-28
        • 1970-01-01
        • 2019-02-23
        • 1970-01-01
        • 2018-10-08
        • 2015-12-21
        相关资源
        最近更新 更多