I'm working on a really simple project in Java to try to understand how to use KeyListener.
I've created a Main class and a KeyListener, MouseListener class. I want to get something to happen when I press a keyboard key. So far the only thing that is working is "Hello" when I click.
Here is my code:
import javax.swing.JFrame;
import javax.swing.JPanel;
public class KeyPractice{
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.addKeyListener(new KeyEar());
panel.addMouseListener(new KeyEar());
frame.add(panel);
frame.setVisible(true);
frame.setSize(400, 400);
}
}
And the Keylistener class....
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class KeyEar implements KeyListener, MouseListener {
public KeyEar(){
}
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("Hello");
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent arg0) {
System.out.println("Hello");
}
#Override
public void keyReleased(KeyEvent arg0) {
System.out.println("Hello");
}
#Override
public void keyTyped(KeyEvent arg0) {
System.out.println("Hello");
}
}
JPanel isn't focusable JComponent, have to add Object/JComponents that is focusable or interact with KeyEvents
KeyListener isn't proper listener for Swing JComponents, for Swing is replaced with KeyBindings
A JPanel cannot gain focus for KeyListener to work.
The preferred approach is to use Key Bindings for Swing. You can map an Action to a KeyStroke even when a component doesn't have focus.
Key Binding Example
I had similar problem but its so simple to solve but you have to found how to solve it witch is not so easy task :D
so how to solve this ? I just set all my buttons as focusable false.
instanceOfYourButton.setFocusable(false);
thats it
Related
I do not know why this doesn't work. I have already read many posts, and added setFocusable but it just does not work.
public class Spiel {
public static void main(String[] args) {
Playground pg = new Playground();
pg.setLocation(0,0);
pg.setSize(1000,1000);
pg.setVisible(true);
pg.setFocusable(true);
}
}
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class Playground extends JFrame implements KeyListener {
Playground(){
}
#Override
public void keyTyped(KeyEvent e) {
System.exit(0);
}
#Override
public void keyPressed(KeyEvent e) {
System.exit(0);
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
You only implemented the KeyListener but if you want it to actually work you still need to register it to your frame.
Playground(){
addKeyListener(this); // should do the trick
}
Otherwise your frame wouldn't know that it actually has to listen and call the methods when a key is pressed.
I'm trying to add a keylistener to JFrame but whenever I click a button, nothing happens. I am trying to get the keylistener to just print something basic but whenever i try to use an if statement nothing happens in the console.
package gui;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.JButton;
public class KeyListener implements java.awt.event.KeyListener {
ArrayList <JButton> _buttons;
JFrame _frame1;
public KeyListener(ArrayList <JButton> buttons, JFrame frame1){
_buttons = buttons;
_frame1 = frame1;
_frame1.addKeyListener(this);
_frame1.requestFocusInWindow();
_frame1.setFocusable(true);
this.keyTyped();
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_LEFT){
System.out.println("yes");
}
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
That is my keylistener class
This is my game class
package model;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Game implements Runnable{
KeyListener _keylistener;
#Override
public void run() {
JFrame frame1 = new JFrame("KeyBricks");
frame1.setVisible(true);
JPanel panel1 = new JPanel();
frame1.addKeyListener(_keylistener);
model.Board board = new model.Board(panel1);
frame1.add(panel1);
frame1.pack();
frame1.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
You could register a KeyEventDispatcher:
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
System.out.println("dispatchKeyEvent: "+e);
return false;
}
});
Note that the registered KeyEventDispatchers will receive KeyEvents before they are dispatched to their targets, allowing to retarget the event, consume it, dispatch the event itself, or make other changes.
I'm trying to make an easy Java program, but I cannot get any inpute from it. Can anyone suggest a solution?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
class KeyIns extends JFrame implements KeyListener {
public void KeyIns(){
addKeyListener(this); //==> this is why ....
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
System.out.println("1");
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
System.out.println("2");
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
System.out.println("2");
}
}
public class Hello {
public static void main(String[] args){
KeyIns inkey = new KeyIns();
inkey.setSize(368, 300);
inkey.setLocation(250, 250);
inkey.setVisible(true);
}
}
KeyListener will only respond if the component it is registered to is both focusable and has focus.
The other problem is JFrame contains a bunch of other components on top of it, including the root pane and content pane. Registering a KeyListener to the frame is probably never going to achieve anything
A better solution would be to use the Key bindings API
A lot will matter based on what it is you are trying to achieve
The problem is you are never invoking the method
public void KeyIns(){
addKeyListener(this); //==> this is why ....
}
Either invoke the method KeyIns() or remove the word void (so that it becomes constructor) like this
public KeyIns(){
addKeyListener(this); //==> this is why ....
}
I am making an app that will have some 'rectangles' (myLabel) with a text (rectangleName). Whenever I click on that rectangle, a combobox (nameComboBox) is shown to change the name of it.
So this is the declaration of that class.
public class myLabel extends JLabel implements MouseListener,FocusListener{
//this.panel;
JComboBox nameComboBox;
String rectangleName;
I added some focus stuff to that class as you can see it implements FocusListener.
I want to show the combobox only when the recangle is focused and hide it otherwise. The problem that I have is that when I select a rectangle and it shows the combobox because it's focused, when I click on the combobox, the rectangle loses its focus so it hides the combobox. Any way to prevent this?
Edit:
Replying to #mKorbel, This is my SSCCE
import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class MyJLabel extends JLabel implements MouseListener,FocusListener{
JComboBox nameComboBox;
JPanel mainPanel;
String name;
public MyJLabel() {
this.setLocation(10,10);
this.setBounds(20, 20,200,200);
this.setBackground(Color.LIGHT_GRAY);
this.setFocusable(true);
setOpaque(true);
setHorizontalAlignment(SwingConstants.CENTER);
setFont(getFont());
setText(this.name);
this.nameComboBox= new JComboBox(new String[] { "option1","option2","option3" });
this.nameComboBox.setBounds(40,40,100,50);
this.nameComboBox.setVisible(false);
this.addMouseListener(this);
this.addFocusListener(this);
}
#Override
public void focusGained(FocusEvent e) {
System.out.println("focus gained");
this.nameComboBox.setVisible(true);
}
#Override
public void focusLost(FocusEvent e) {
System.out.println("focus lost");
this.nameComboBox.setVisible(false);
}
#Override
public void mouseClicked(MouseEvent e) {
this.requestFocus();
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
MyJLabel myjl=new MyJLabel();
JFrame fr = new JFrame();
fr.setLayout(null);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComboBox otherCombo = new JComboBox(new String[] { "otherOption1","otherOption2","otherOption3" });
otherCombo.setBounds(40,400,100,50);
fr.add(myjl.nameComboBox);
fr.add(myjl);
fr.add(otherCombo);
fr.setSize(300,500);
fr.setVisible(true);
}
}
You must start clicking on the combo at the bottom and you'll see in the console that the focus is lost. click on the gray rectangle and the focus will be gained. Click on the combo inside the rectangle and the rectangle will lose and gain the focus instantly, so it's impossible to choose an item. I would like to not change the focus of the rectangle while I am interacting with its combobox.
I need help to understand the event propagation in Swing. I know that each event is handled by only one component. Thus, when I have a panel outside with some child panel inside and I add mouseListeners to both of them, the one of inside will be called. That's nice and that's the expected behavior.
But I don't understand the behavior in the following situation:
inside registers a MouseMotionListener and outside registers a MouseListener. I expect inside to consume all MouseMotionEvents and outside to receive the MouseEvents, because there is no listener for normal MouseEvents on inside. But that's not the case, inside somehow consumes all MouseEvents not only the MouseMotionEvents.
The following code illustrates the problem:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventTest {
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
JComponent inside = new JPanel();
inside.setBackground(Color.red);
inside.setPreferredSize(new Dimension(200,200));
MouseMotionListener mm = new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent arg0) {
System.err.println("dragged");
}
#Override
public void mouseMoved(MouseEvent arg0) {
System.err.println("moved");
}
};
// next line disables handling of mouse clicked events in outside
inside.addMouseMotionListener(mm);
JComponent outside = new JPanel();
outside.add(inside);
outside.setPreferredSize(new Dimension(300,300));
outside.addMouseListener( new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.err.println("clicked");
}
});
JFrame frame = new JFrame();
frame.add(outside);
frame.pack();
frame.setVisible(true);
}
});
}
}
I could work around the problem by registering a listeners on inside for all events the parent component might be interested in and then calling dispatchEvent to forward the event to the parent.
a) can someone point me to some docs, where this behavior is described? The javadocs of MouseEvent made me think that my expectations were right. So, I need a different description to understand it.
b) is there a better solution than the one sketched above?
Thanks,
Kathrin
Edit: It is still unclear, why Swing behaves this way. But as it looks, the only way to get the stuff working is to manually forward the events, I will do it.
a) By design, Java mouse events "bubble up" only if there in no mouse listener on the child component.
b) You can forward events to another component, as shown here and below.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventTest {
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JComponent outside = new JPanel();
JComponent inside = new JPanel();
inside.setBackground(Color.red);
inside.setPreferredSize(new Dimension(200, 200));
inside.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
System.err.println("dragged");
}
#Override
public void mouseMoved(MouseEvent e) {
System.err.println("moved inside");
outside.dispatchEvent(e);
}
});
outside.add(inside);
outside.setPreferredSize(new Dimension(300, 300));
outside.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent arg0) {
System.err.println("moved outside");
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(outside);
frame.pack();
frame.setVisible(true);
}
});
}
}
Very similar to trashgod's answer - you can use a MouseAdapter as your motion listener, and override it to forward any events you want to be handled by the parent. This should only add a minimal amount to your code.
MouseAdapter mm = new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent arg0) {
System.err.println("dragged");
}
#Override
public void mouseMoved(MouseEvent arg0) {
System.err.println("moved");
}
#Override
public void mouseClicked(MouseEvent e) {
outside.dispatchEvent(e);
}
};
// For forwarding events
inside.addMouseListener(mm);
// For consuming events you care about
inside.addMouseMotionListener(mm);
I too couldn't find any way around using the dispatchEvent(e) method. I think you're stuck with that route.
This worked out for me:
Ellipse2D mCircle = new Ellipse2D.Double(x,y,size,size);
void PassMouseEvent(MouseEvent e) {
getParent().dispatchEvent(e);
}
public void mousePressed(MouseEvent arg0) {
if(mCircle.contains(arg0.getX(), arg0.getY())) {
// Do stuff if we click on this object
} else {
// Pass to the underlying object to deal with the mouse event
PassMouseEvent(arg0);
}
}