0

I have this class and I want to switch focus to the Game class right after it was invoked. I might've not understand the purpose of focus but when I press start I have to click on the game canvas itself so I can use the keyboard . In other words: How can I make it so I don't have to click on it to use the keyboard?

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");
            }
        });
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Andrew V
  • 522
  • 10
  • 24
  • so Game extends from canvas? – Rod_Algonquin Aug 10 '14 at 08:57
  • [How to Use the Focus Subsystem](http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html) – Braj Aug 10 '14 at 08:57
  • 1) Swing GUIs might have to work on different platforms, using different PLAFs, on different screen sizes and resolutions with different default settings for font size. As such, they are not conducive to exact placement of components. Instead use layout managers, or [combinations of layout managers](http://stackoverflow.com/a/5630271/418556) as well as [layout padding and borders](http://stackoverflow.com/q/17874717/418556) for white space. 2) For Swing, we typically use [key bindings](http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html) over the lower level `KeyListener`. – Andrew Thompson Aug 10 '14 at 09:23

3 Answers3

1

Off topic: (kinda)

The fact that you are doing Main.mainp.getLayout();, calling the panel statically tells me you have poor design and should be looking into other options like an Model-view-controller pattern, an Observer pattern, or at the very least passing a reference of of the Main to the panel, instead of using static objects/calls.

Back on topic

Sounds like a common KeyListener problem. Generally to gain focus you call requestFocusInWindow(). But you still have to worry about other components stealing the focus way after the fact.

I would instead recommend using Key Bindings instead of KeyListener. You have more control over the focus. For instance, by using

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

The panel will have immediate access to the action once you show it from the CardLayout. If you happen to use any other components that would steal the focus away from the panel, the action is still accessible because of the WHEN_IN_FOCUSED_WINDOW input map

Here's a simple example. Type A if it is on panel A, you will see it print. If you type B, it won't print because panel A is in the window. Also if you try and press the button in the panel to steal the focus, you can still type and it will still print. Same goes for panel 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();
            }
        });
    }
}

Take some time to go over the link I gave you for Key Bindings to learn more.

Back off-topic

Take a look at @AndrewThompson's comment about the null layouts. Learn how to use the LayoutManagers

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
0

I believe your problem would be fixed if you add

setFocusable(true);

to your PlayPanel constructor (works for me). Also, if you want a specific Panel in your GUI to have focus when you start your application, follow the link in the comment of "user3218114", as this will explain how to implement this functionality with Listeners.

Good luck!

MrMalt
  • 42
  • 7
0

You don't need to do anything. The container should be focusable for that.
Here is a code to demonstrate.

package one;

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);
    }
}
afzalex
  • 8,598
  • 2
  • 34
  • 61