Is it possible to clear a listener that I put on my JPanel? When I call a method, I put a KeyListener on the panel but when I quit this method, I want to clear that listener.
Here is my method :
private void stopBall(final Graphics2D g2, int posBallY, String winner) {
move = false;
scorePanel.showPressSpace(true);
setFocusable(true);
requestFocus();
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e){
if (e.getKeyCode() == KeyEvent.VK_SPACE){
setPosX(getPlayPanelWidth()/2);
setPosY(0);
move = true;
scorePanel.showPressSpace(false);
initBall(g2);
}
}});
if (winner == "player1") {
scoreCountPlayer1++;
scorePanel.getLab_Player1().setText("" + scoreCountPlayer1);
} else if (winner == "comp") {
scoreCountComputer++;
scorePanel.getLab_Computer().setText("" + scoreCountComputer);
}
}
You have an unqualified call to addKeyListener(KeyListener), so I presume that you've extended JPanel. If so, then you can call removeKeyListener(KeyListener). In your current code, your key listener is anonymous. You'll need to change it just a bit to hold on to that reference, like so:
// Create a variable holding the listener
KeyAdapter keyAdapter = new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
setPosX(getPlayPanelWidth() / 2);
setPosY(0);
move = true;
scorePanel.showPressSpace(false);
initBall(g2);
}
}
};
// Register the listener with this JPanel
addKeyListener(keyAdapter);
// Time passes...
// Remove the listener from this JPanel
removeKeyListener(keyAdapter);
Or the way with the absolute minimal adjustments to your code
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e){
if (e.getKeyCode() == KeyEvent.VK_SPACE){
((JPanel)e.getSource()).removeKeyListener( this );
setPosX(getPlayPanelWidth()/2);
setPosY(0);
move = true;
scorePanel.showPressSpace(false);
initBall(g2);
}
}
});
But as already stated in the comments, you should opt for keybindings instead of keylisteners
Related
I'm trying to implement a KeyListener for my JFrame. On the constructor, I'm using this code:
System.out.println("test");
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) { System.out.println( "tester"); }
public void keyReleased(KeyEvent e) { System.out.println("2test2"); }
public void keyTyped(KeyEvent e) { System.out.println("3test3"); }
});
When I run it, the test message comes up in my console. However, when I press a key, I don't get any of the other messages, as if the KeyListener was not even there.
I was thinking that it could be because the focus is not on the JFrame
and so they KeyListener doesn't receive any events. But, I'm pretty sure it is.
Is there something that I am missing?
If you don't want to register a listener on every component,
you could add your own KeyEventDispatcher to the KeyboardFocusManager:
public class MyFrame extends JFrame {
private class MyDispatcher implements KeyEventDispatcher {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
System.out.println("tester");
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
System.out.println("2test2");
} else if (e.getID() == KeyEvent.KEY_TYPED) {
System.out.println("3test3");
}
return false;
}
}
public MyFrame() {
add(new JTextField());
System.out.println("test");
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new MyDispatcher());
}
public static void main(String[] args) {
MyFrame f = new MyFrame();
f.pack();
f.setVisible(true);
}
}
You must add your keyListener to every component that you need. Only the component with the focus will send these events. For instance, if you have only one TextBox in your JFrame, that TextBox has the focus. So you must add a KeyListener to this component as well.
The process is the same:
myComponent.addKeyListener(new KeyListener ...);
Note: Some components aren't focusable like JLabel.
For setting them to focusable you need to:
myComponent.setFocusable(true);
InputMaps and ActionMaps were designed to capture the key events for the component, it and all of its sub-components, or the entire window. This is controlled through the parameter in JComponent.getInputMap(). See How to Use Key Bindings for documentation.
The beauty of this design is that one can pick and choose which key strokes are important to monitor and have different actions fired based on those key strokes.
This code will call dispose() on a JFrame when the escape key is hit anywhere in the window. JFrame doesn't derive from JComponent so you have to use another component in the JFrame to create the key binding. The content pane might be such a component.
InputMap inputMap;
ActionMap actionMap;
AbstractAction action;
JComponent component;
inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
actionMap = component.getActionMap();
action = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
dispose();
}
};
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "dispose");
actionMap.put("dispose", action);
I got the same problem until i read that the real problem is about FOCUS the your JFrame has already added Listeners but tour frame is never on Focus because you got a lot of components inside your JFrame that also are focusable so try:
JFrame.setFocusable(true);
Good Luck
KeyListener is low level and applies only to a single component. Despite attempts to make it more usable JFrame creates a number of component components, the most obvious being the content pane. JComboBox UI is also often implemented in a similar manner.
It's worth noting the mouse events work in a strange way slightly different to key events.
For details on what you should do, see my answer on Application wide keyboard shortcut - Java Swing.
Deion (and anyone else asking a similar question), you could use Peter's code above but instead of printing to standard output, you test for the key code PRESSED, RELEASED, or TYPED.
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
if (e.getKeyCode() == KeyEvent.VK_F4) {
dispose();
}
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
if (e.getKeyCode() == KeyEvent.VK_F4) {
dispose();
}
} else if (e.getID() == KeyEvent.KEY_TYPED) {
if (e.getKeyCode() == KeyEvent.VK_F4) {
dispose();
}
}
return false;
}
in order to capture key events of ALL text fields in a JFrame,
one can employ a key event post processor.
Here is a working example, after you add the obvious includes.
public class KeyListenerF1Demo extends JFrame implements KeyEventPostProcessor {
public static final long serialVersionUID = 1L;
public KeyListenerF1Demo() {
setTitle(getClass().getName());
// Define two labels and two text fields all in a row.
setLayout(new FlowLayout());
JLabel label1 = new JLabel("Text1");
label1.setName("Label1");
add(label1);
JTextField text1 = new JTextField(10);
text1.setName("Text1");
add(text1);
JLabel label2 = new JLabel("Text2");
label2.setName("Label2");
add(label2);
JTextField text2 = new JTextField(10);
text2.setName("Text2");
add(text2);
// Register a key event post processor.
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventPostProcessor(this);
}
public static void main(String[] args) {
JFrame f = new KeyListenerF1Demo();
f.setName("MyFrame");
f.pack();
f.setVisible(true);
}
#Override
public boolean postProcessKeyEvent(KeyEvent ke) {
// Check for function key F1 pressed.
if (ke.getID() == KeyEvent.KEY_PRESSED
&& ke.getKeyCode() == KeyEvent.VK_F1) {
// Get top level ancestor of focused element.
Component c = ke.getComponent();
while (null != c.getParent())
c = c.getParent();
// Output some help.
System.out.println("Help for " + c.getName() + "."
+ ke.getComponent().getName());
// Tell keyboard focus manager that event has been fully handled.
return true;
}
// Let keyboard focus manager handle the event further.
return false;
}
}
This should help
yourJFrame.setFocusable(true);
yourJFrame.addKeyListener(new java.awt.event.KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
System.out.println("you typed a key");
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("you pressed a key");
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("you released a key");
}
});
Hmm.. what class is your constructor for? Probably some class extending JFrame? The window focus should be at the window, of course but I don't think that's the problem.
I expanded your code, tried to run it and it worked - the key presses resulted as print output. (run with Ubuntu through Eclipse):
public class MyFrame extends JFrame {
public MyFrame() {
System.out.println("test");
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
System.out.println("tester");
}
public void keyReleased(KeyEvent e) {
System.out.println("2test2");
}
public void keyTyped(KeyEvent e) {
System.out.println("3test3");
}
});
}
public static void main(String[] args) {
MyFrame f = new MyFrame();
f.pack();
f.setVisible(true);
}
}
I have been having the same problem. I followed Bruno's advice to you and found that adding a KeyListener just to the "first" button in the JFrame (ie, on the top left) did the trick. But I agree with you it is kind of an unsettling solution. So I fiddled around and discovered a neater way to fix it. Just add the line
myChildOfJFrame.requestFocusInWindow();
to your main method, after you've created your instance of your subclass of JFrame and set it visible.
lol .... all you have to do is make sure that
addKeyListener(this);
is placed correctly in your code.
You could have custom JComponents set their parent JFrame focusable.
Just add a constructor and pass in the JFrame. Then make a call to setFocusable() in paintComponent.
This way the JFrame will always receive KeyEvents regardless of whether other components are pressed.
I have a Graphics project that contains KeyListener, where the arrow keys and space bar controls the movement of a spaceship. However, when a key is held down, it registers the next key presses after a delay after the first. I would like for a held down key to register continuously.
I suspect that this is due to my computer's setting for key repeat delay, so is there any way to temporarily override this in my program, or a workaround for it?
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 38) { //Up Arrow
currentLevel.moveSpiffUp();
} else if (e.getKeyCode() == 40) { //Down Arrow
currentLevel.moveSpiffDown();
} else if (e.getKeyCode() == 32 && !currentLevel.getFrapRayActive()) {
currentLevel.shoot();
}
repaint();
}
I would suggest using key press and key released
public class MyKeyListener implements KeyListener {
//class gets the input from the player
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(KeyEvent.getKeyText(e.getKeyCode()).equals("Left")) {
//left arrow key
} else if (KeyEvent.getKeyText(e.getKeyCode()).equals("Right")) {
//right arrow key
}
}
public void keyReleased(KeyEvent e) {
if(KeyEvent.getKeyText(e.getKeyCode()).equals("Left"){
//left key released
}
if(KeyEvent.getKeyText(e.getKeyCode()).equals("Right")) {
//right key released
}
}
}
I then used this bit of code in my main constructor
main() {
KeyListener listener = new MyKeyListener();
addKeyListener(listener);
setFocusable(true);
}
This way you wont have your delay when hitting keys.
How do I use MouseListener and KeyListener at the same time?
For example, how to do something like this
public void keyPressed( KeyEvent e){
// If the mouse button is clicked while any key is held down, print the key
}
Use a boolean value for whether a mouse button is held down, and then update that variable in a MouseListener.
boolean buttonDown = false;
public class ExampleListener implements MouseListener {
public void mousePressed(MouseEvent e) {
buttonDown = true;
}
public void mouseReleased(MouseEvent e) {
buttonDown = false;
}
//Other implemented methods unimportant to this post...
}
Then, in your KeyListener class, just test the buttonDown variable.
Try creating a boolean isKeyPressed. In keyPressed, set it to true and in keyReleased set it to false. Then, when the mouse is clicked, first check if isKeyPressed is true.
You could try checking the state of the KeyEvent modifiers, for example...
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
int mods = e.getModifiers();
System.out.println(mods);
if ((mods & KeyEvent.BUTTON1_MASK) != 0) {
System.out.println("Button1 down");
}
}
});
I should also point out, you can do...
int ext = e.getModifiersEx();
if ((ext & KeyEvent.BUTTON1_DOWN_MASK) != 0) {
System.out.println("Button1_down_mask");
}
Which, as I've just discovered, produces results for other mouse buttons...
I am currently trying to implement a keylistener in my program so that it does an action when I pressed an arrow key, the object in my program either moves left or right.
Here is the moving method in my program
public void moveDirection(KeyEvent e)
{
int move = 0;
int r = K.getRow();
int c = K.getCol();
if (e.getKeyCode() == 39) move = 1; //KeyEvent.VK_RIGHT
if (e.getKeyCode() == 37) move = 2; //KeyEvent.VK_LEFT
//if (e.getKeyCode() == KeyEvent.VK_DOWN) move = 3;
switch (move)
{
case 1: if (inBound(r, c+1))
K.setLocation(r ,c+1);
if (inBound(r, c-1) && frame2[r][c-1] == K)
frame2[K.getRow()][K.getCol()-1] = null;
break; //move right 39
case 2: K.setLocation(K.getRow(), K.getCol()-1); break; //move left 37
//case 3: b.setLocation(b.getRow()+1, b.getCol()); break; //move down
default: return;
}
processBlockList();
}
I am wondering how the program is supposed to read in (KeyEvent) e. I cannot really type in an arrowkey....
Please help!
edit: I also need to know what I need to add to my code so that my program waits about 700 milliseconds for a keyinput before moving on to another method
http://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html
Check this tutorial
If it's a UI based application , then " I also need to know what I need to add to my code so that my program waits about 700 milliseconds for a keyinput before moving on to another method" you can use GlassPane or Timer class to fulfill the requirement.
For key Event:
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = -1;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 1;
}
if (key == KeyEvent.VK_UP) {
dy = -1;
}
if (key == KeyEvent.VK_DOWN) {
dy = 1;
}
}
check this game example http://zetcode.com/tutorials/javagamestutorial/movingsprites/
Here is an SSCCE,
package experiment;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class KeyListenerTester extends JFrame implements KeyListener {
JLabel label;
public KeyListenerTester(String s) {
super(s);
JPanel p = new JPanel();
label = new JLabel("Key Listener!");
p.add(label);
add(p);
addKeyListener(this);
setSize(200, 100);
setVisible(true);
}
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right key typed");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left key typed");
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right key pressed");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left key pressed");
}
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right key Released");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left key Released");
}
}
public static void main(String[] args) {
new KeyListenerTester("Key Listener Tester");
}
}
Additionally read upon these links : How to Write a Key Listener and How to Use Key Bindings
The class which implements KeyListener interface becomes our custom key event listener. This listener can not directly listen the key events. It can only listen the key events through intermediate objects such as JFrame. So
Make one Key listener class as
class MyListener implements KeyListener{
// override all the methods of KeyListener interface.
}
Now our class MyKeyListener is ready to listen the key events. But it can not directly do so.
Create any object like JFrame object through which MyListener can listen the key events. for that you need to add MyListener object to the JFrame object.
JFrame f=new JFrame();
f.addKeyListener(new MyKeyListener);
In addition to using KeyListener (as shown by others' answers), sometimes you have to ensure that the JComponent you are using is Focusable. This can be set by adding this to your component(if you are subclassing):
#Override
public void setFocusable(boolean b) {
super.setFocusable(b);
}
And by adding this to your constructor:
setFocusable(true);
Or, if you are calling the function from a parent class/container:
JComponent childComponent = new JComponent();
childComponent.setFocusable(true);
And then doing all the KeyListener stuff mentioned by others.
I'm trying to implement a KeyListener for my JFrame. On the constructor, I'm using this code:
System.out.println("test");
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) { System.out.println( "tester"); }
public void keyReleased(KeyEvent e) { System.out.println("2test2"); }
public void keyTyped(KeyEvent e) { System.out.println("3test3"); }
});
When I run it, the test message comes up in my console. However, when I press a key, I don't get any of the other messages, as if the KeyListener was not even there.
I was thinking that it could be because the focus is not on the JFrame
and so they KeyListener doesn't receive any events. But, I'm pretty sure it is.
Is there something that I am missing?
If you don't want to register a listener on every component,
you could add your own KeyEventDispatcher to the KeyboardFocusManager:
public class MyFrame extends JFrame {
private class MyDispatcher implements KeyEventDispatcher {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
System.out.println("tester");
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
System.out.println("2test2");
} else if (e.getID() == KeyEvent.KEY_TYPED) {
System.out.println("3test3");
}
return false;
}
}
public MyFrame() {
add(new JTextField());
System.out.println("test");
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
manager.addKeyEventDispatcher(new MyDispatcher());
}
public static void main(String[] args) {
MyFrame f = new MyFrame();
f.pack();
f.setVisible(true);
}
}
You must add your keyListener to every component that you need. Only the component with the focus will send these events. For instance, if you have only one TextBox in your JFrame, that TextBox has the focus. So you must add a KeyListener to this component as well.
The process is the same:
myComponent.addKeyListener(new KeyListener ...);
Note: Some components aren't focusable like JLabel.
For setting them to focusable you need to:
myComponent.setFocusable(true);
InputMaps and ActionMaps were designed to capture the key events for the component, it and all of its sub-components, or the entire window. This is controlled through the parameter in JComponent.getInputMap(). See How to Use Key Bindings for documentation.
The beauty of this design is that one can pick and choose which key strokes are important to monitor and have different actions fired based on those key strokes.
This code will call dispose() on a JFrame when the escape key is hit anywhere in the window. JFrame doesn't derive from JComponent so you have to use another component in the JFrame to create the key binding. The content pane might be such a component.
InputMap inputMap;
ActionMap actionMap;
AbstractAction action;
JComponent component;
inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
actionMap = component.getActionMap();
action = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
dispose();
}
};
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "dispose");
actionMap.put("dispose", action);
I got the same problem until i read that the real problem is about FOCUS the your JFrame has already added Listeners but tour frame is never on Focus because you got a lot of components inside your JFrame that also are focusable so try:
JFrame.setFocusable(true);
Good Luck
KeyListener is low level and applies only to a single component. Despite attempts to make it more usable JFrame creates a number of component components, the most obvious being the content pane. JComboBox UI is also often implemented in a similar manner.
It's worth noting the mouse events work in a strange way slightly different to key events.
For details on what you should do, see my answer on Application wide keyboard shortcut - Java Swing.
Deion (and anyone else asking a similar question), you could use Peter's code above but instead of printing to standard output, you test for the key code PRESSED, RELEASED, or TYPED.
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
if (e.getKeyCode() == KeyEvent.VK_F4) {
dispose();
}
} else if (e.getID() == KeyEvent.KEY_RELEASED) {
if (e.getKeyCode() == KeyEvent.VK_F4) {
dispose();
}
} else if (e.getID() == KeyEvent.KEY_TYPED) {
if (e.getKeyCode() == KeyEvent.VK_F4) {
dispose();
}
}
return false;
}
in order to capture key events of ALL text fields in a JFrame,
one can employ a key event post processor.
Here is a working example, after you add the obvious includes.
public class KeyListenerF1Demo extends JFrame implements KeyEventPostProcessor {
public static final long serialVersionUID = 1L;
public KeyListenerF1Demo() {
setTitle(getClass().getName());
// Define two labels and two text fields all in a row.
setLayout(new FlowLayout());
JLabel label1 = new JLabel("Text1");
label1.setName("Label1");
add(label1);
JTextField text1 = new JTextField(10);
text1.setName("Text1");
add(text1);
JLabel label2 = new JLabel("Text2");
label2.setName("Label2");
add(label2);
JTextField text2 = new JTextField(10);
text2.setName("Text2");
add(text2);
// Register a key event post processor.
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventPostProcessor(this);
}
public static void main(String[] args) {
JFrame f = new KeyListenerF1Demo();
f.setName("MyFrame");
f.pack();
f.setVisible(true);
}
#Override
public boolean postProcessKeyEvent(KeyEvent ke) {
// Check for function key F1 pressed.
if (ke.getID() == KeyEvent.KEY_PRESSED
&& ke.getKeyCode() == KeyEvent.VK_F1) {
// Get top level ancestor of focused element.
Component c = ke.getComponent();
while (null != c.getParent())
c = c.getParent();
// Output some help.
System.out.println("Help for " + c.getName() + "."
+ ke.getComponent().getName());
// Tell keyboard focus manager that event has been fully handled.
return true;
}
// Let keyboard focus manager handle the event further.
return false;
}
}
This should help
yourJFrame.setFocusable(true);
yourJFrame.addKeyListener(new java.awt.event.KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
System.out.println("you typed a key");
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("you pressed a key");
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("you released a key");
}
});
Hmm.. what class is your constructor for? Probably some class extending JFrame? The window focus should be at the window, of course but I don't think that's the problem.
I expanded your code, tried to run it and it worked - the key presses resulted as print output. (run with Ubuntu through Eclipse):
public class MyFrame extends JFrame {
public MyFrame() {
System.out.println("test");
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
System.out.println("tester");
}
public void keyReleased(KeyEvent e) {
System.out.println("2test2");
}
public void keyTyped(KeyEvent e) {
System.out.println("3test3");
}
});
}
public static void main(String[] args) {
MyFrame f = new MyFrame();
f.pack();
f.setVisible(true);
}
}
I have been having the same problem. I followed Bruno's advice to you and found that adding a KeyListener just to the "first" button in the JFrame (ie, on the top left) did the trick. But I agree with you it is kind of an unsettling solution. So I fiddled around and discovered a neater way to fix it. Just add the line
myChildOfJFrame.requestFocusInWindow();
to your main method, after you've created your instance of your subclass of JFrame and set it visible.
lol .... all you have to do is make sure that
addKeyListener(this);
is placed correctly in your code.
You could have custom JComponents set their parent JFrame focusable.
Just add a constructor and pass in the JFrame. Then make a call to setFocusable() in paintComponent.
This way the JFrame will always receive KeyEvents regardless of whether other components are pressed.