I am writing a simple java snake-like game, and I ran into a problem even before I actually got to making the game. I can't seem to get input from the keyboard for some reason. My current code is:
public class GameWindow extends JFrame{
private SnakeCanvas snakeCanvas;
public GameWindow(StartWindow sw) {
getContentPane().addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
JOptionPane.showMessageDialog(null, "Key Pressed!");
}
});
getContentPane().setBackground(Color.BLACK);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setUndecorated(true);
this.setVisible(true);
getContentPane().setLayout(null);
snakeCanvas = new SnakeCanvas();
snakeCanvas.setBounds(78, 72, 290, 195);
getContentPane().add(snakeCanvas);
snakeCanvas.setVisible(true);
snakeCanvas.repaint();
}
}
(a SnakeCanvas extends JPanel and has no other components on it)
I've tried also adding a key listener to the snakeCanvas and still no effect..
I've also tried to play with the focusable and the focus Traversal stuff but that also didn't do anything...
Can anyone please explain to me what I'm doing wrong?
Make sure you have set the components you want to receive keyboard events is focusable (setFocusable) & has focus (requestFocus)
KeyListener isn't proper listener for Swing JComponents, required focus in the window
you have to setFocusable for container
right and correct way is usage of KeyBindings, for example
Related
I have tried this code to draw a string on my frame using KeyListener interface such that whenever I hit a typeable key on keyboard, it should appear on frame but it doesn't work even though there are no errors.
Can someone tell what's the mistake?
Below is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class KeyevntFrame2 extends Frame {
Button b = new Button("ok");
Button b1 = new Button("hey");
char ch;
String s = "";
public KeyevntFrame2() {
setTitle("understand key events");
setSize(800, 600);
addKeyListener(new KeyHandler());
setFont(new Font("Arial", Font.PLAIN, 35));
setForeground(Color.BLACK);
add(b);
add(b1);
b.setBounds(200, 200, 100, 100);
b1.setBounds(200, 700, 100, 100);
setLayout(null);
b.addActionListener(new KeyHandler());
b1.addActionListener(new KeyHandler());
}
class KeyHandler implements KeyListener, ActionListener {
public void keyPressed(KeyEvent e) {
ch = e.getKeyChar();
s = s + ch;
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void paint(Graphics g) {
g.drawString(s, 300, 200);
g.setFont(new Font("Arial", Font.PLAIN, 35));
}
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(b1, "thank you for using java");
}
}
public static void main(String a[]) {
KeyevntFrame2 f = new KeyevntFrame2();
f.setVisible(true);
}
}
Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or combinations of them along with layout padding and borders for white space. This advice is especially relevant to this GUI, given that the frame does not have enough height to display the second button.
Don't mix AWT (Frame) and Swing (JOptionPane) components in one GUI. Choose a GUI toolkit and stick with it.
Always use #Override notation when changing the behavior of existing methods or implementing the methods of an interface. Doing so would have warned you that neither the KeyListener nor ActionListener interfaces define a public void paint(Graphics) method!
Defining a combined KeyListener and ActionListener does not make much sense, and has confused you into thinking that calling Button.addActionListener(..) with the combined listener will also have the effect of adding it as a KeyListener. It won't.
new Font("Arial", Font.PLAIN, 35) for cross-platform robustness, that should be new Font(Font.SANS_SERIF, Font.PLAIN, 35) (e.g OS X will typically not have the Arial font installed, and users would prefer to see Helvetica in any case.)
It is not necessary to set the font of the frame, and also the font in the paint method. Just do it once in the frame.
Since the frame itself is not focusable, calling addKeyListener(..) will have no effect. Better to use Swing and implement key bindings in any case.
When custom painting, always call the super method first.
Swing and AWT GUIs should be started on the EDT.
"it doesn't work even though there are no errors." There are plenty of errors in the code seen above, it's just that they are neither compilation errors, nor run-time errors that throw exceptions. Plenty can still go wrong with code even if the compiler or virtual machine does not identify them. This is why 'cut & paste' coding sans understanding what the code does, never works. Hit the tutorials and read the Java docs.
I have a JFrame called gameFrame and I added a Jpanel called introPanel to it, gameFrame.add(introPanel) and I wanted to listen to the JPanel with a keylistener so I added one. When the user presses Enter, I removed the JPanel from the gameFrame and added the MainMenu theoretically, however the program doesnt listen to my keys. So i looked online and through SO and found out that I had to make the panel focusable so I did:
public IntroMenuStart() {
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
However this did not work either. What else can I do to fix this?
Each Panel is a seperate class and they all get removed from gameframe and the next panel is added.
I would prefer to do this with keylistener.
EDIT
I fixed it by including this in my code for anyone wanting to know but I'm going to be changing my code to Keybindings like the 2 answers suggsted.
public void addNotify() {
super.addNotify();
requestFocus();
}
i want to listne to the panel with a key listener so i add one. When
the user presses Enter, i remove to JPanel form the gameFrame and add
MainMenu, theoretically, however the program doesnt listen to my keys
If you search in deep in SO , you'll see that you have to use KeyBindings
KeyListener has 2 greate issues, you listen to all keys and you have to have focus.
Instead KeyBinding you bind for a key and you don't have to be in focus.
Simple Example:
AbstractAction escapeAction = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//code here example
((JComponent)e.getSource()).setVisible(Boolean.FALSE);
}};
String key = "ESCAPE";
KeyStroke keyStroke = KeyStroke.getKeyStroke(key);
component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, key);
component.getActionMap().put(key, escapeAction);
You can use these JComponent constants
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
WHEN_FOCUSED
WHEN_IN_FOCUSED_WINDOW
I believe that JPanel is not focuseable. Instead, use the key bindings.
See How to Use Key Bindings.
I have a subclass of JFrame that uses a class extended from JPanel
public class HelloWorld extends JPanel implements KeyListener
I add an object of HelloWorld to the frame - app.add(helloWorld);. Now, when I press any keyboard key non of the KeyListener methods gets called and it seems that helloWorld doesn't have window focus. I have tried also to invoke helloWorld.requestFocusInWindow(); but still doesn't respond.
How can I make it respond to key press?
Did you set that KeyListener for your HelloWorld panel would be that panel itself? Also you probably need to set that panel focusable. I tested it by this code and it seems to work as it should
class HelloWorld extends JPanel implements KeyListener{
public void keyTyped(KeyEvent e) {
System.out.println("keyTyped: "+e);
}
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed: "+e);
}
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased: "+e);
}
}
class MyFrame extends JFrame {
public MyFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(200,200);
HelloWorld helloWorld=new HelloWorld();
helloWorld.addKeyListener(helloWorld);
helloWorld.setFocusable(true);
add(helloWorld);
setVisible(true);
}
public static void main(String[] args) {
new MyFrame();
}
}
JPanel is not Focusable by default. That is, it can not respond to focus related events, meaning that it can not respond to the keyevents.
I would suggest trying to setFocusable on the pane to true and trying again. Make sure you click the panel first to make sure it receives focus.
Understand though, you WILL get strange focus traversal issues, as the panel will now receive input focus as the user navigates through your forms, making it seem like the focus has been lost some where.
Also, KeyListeners tend to be unreliable in this kind of situation (due to the way that the focus manager works).
simple you have to add
addKeylistener(new HelloWorld());
add this in MyFrame method;
HelloWorld() helloWorld = new HelloWorld();
this.addKeyListener(helloWorld);
I'm using a KeyListener on a JFrame object which I set as FullScreenWindow, something like this code:
class Game{
private GraphicsDevice device;
...
public void run(){
JFrame frame = new JFrame();
frame.addKeyListener(new MarioKeyListener());
device.setFullScreenWindow(frame);
}
...
}
And it works fine if I just create a Game object in my main method and call run().
However I want to do this inside the mousePressed() function of a MouseAdapter which I added to another JFrame-s MenuItem. The result is that the program runs as normal but doesn't accept any keyboard input.
JMenu gamemenu = new JMenu("Game");
JMenuItem newGame = new JMenuItem("New Game");
newGame.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e){
Game g = new Game();
g.run();
}
});
gamemenu.add(newGame);
I think My frame object is not in focus, but calling setFocusable(true) and requestfocusinwindow() did not help.
If anyone knows whats wrong or how to fix this, help would be greatly appreciated...
Tomi
requestFocusInWindow()..
Requests that this Component get the input focus, if this Component's top-level ancestor is already the focused Window.
Are you checking the return value? I suspect it is failing because the new window is not the focused component at the moment the method is called.
If that is the case, the answer might be found in similar fashion to the dialog focus strategy of adding a RequestFocusListener to the mix.
I'm having issues giving focus to a JScrollPane. I'm trying to do this when the window is created so that I can try out the key bindings I'm working on. Everything shows up where it's supposed to be and at the correct size. What I've got looks like this:
import java.awt.*;
import java.swing.*;
public class MyInterface extends JFrame {
public MyInterface() {}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
// define custom table model
JTable table = new JTable(model);
MyScrollPane scrollPane = new MyScrollPane(table);
MyInterface frame = new MyInterface();
scrollPane.setPreferredSize(new Dimension(512, 512));
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setVisible();
scrollPane.requestFocus();
}
}
public class MyScrollPane extends JScrollPane implements KeyListener {
public MyScrollPane(Component view) {
super(view, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
}
// key event processing
}
I tried adding a window listener to the frame which would request focus for scrollPane after the window was finished opening, but it didn't help. Any ideas?
EDIT: Thought I should mention that scrollPane.isFocusable() and scrollPane.isRequestFocusEnabled both return true, so I should be able to give it focus.
EDIT: It seems I'm unable to give focus to anything (frame, table, etc.), so there's some other problem here. No matter what I try, this displays null:
Component compFocusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
System.out.println("focus owner: " + compFocusOwner);
I think that not possible to set the Focus to the JScrolPane, but set Focus to the JComponent, which is place into JScrolPane couldn't be problem
Runnable doRun = new Runnable() {
#Override
public void run() {
myComponent.requestFocus();//requestFocusInWindow
myComponent.grabFocus();
}
};
SwingUtilities.invokeLater(doRun);
Why do you need this? I think you should set focus on the component inside the JScrollPane. How do you detect that the focus isn't there? Scrollpane itself has no visible part (may be just 1 pixel frame is visible).
As noted in How to Use Key Bindings: How Key Bindings Work, composite components typically use the WHEN_ANCESTOR_OF_FOCUSED_COMPONENT map. You can even add bindings to the top-level component's root pane, as shown in Key Bindings.
I've no clue what the problem was; for lack of a better idea I deleted and retyped everything, and now it works. It is possible to focus a JScrollPane, in case anyone reading this wishes to. I assumed it was possible, since by default both .isFocusable() and isRequestFocusEnabled() are set to true. But yeah, I have no idea; at the very least I got a few good links for key binding. Thanks for the help!