I want to listen on F3 key pressed inside my JFrame.
How is this possible?
Something like this:
this.addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyCode() == F3)
MyFrame.this.dispose();
}
});
Using solution from Benson99 as a springboard, I think the following should work.
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class KeyListenFrame extends JFrame {
public KeyListenFrame() {
JFrame frame = new JFrame();
frame.setTitle("Key Listener Frame - Press F3 to close frame");
frame.setSize(600, 300);
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_F3) {
System.out.println("Pressed " + e.getKeyCode());
System.out.println("Closing frame");
frame.dispose();
} else {
System.out.println("Pressed " + e.getKeyCode());
}
}
#Override
public void keyReleased(KeyEvent e) {
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
KeyListenFrame keyListenFrame = new KeyListenFrame();
}
}
You have to use keyPressed for the function keys. Try this code and press keys. Function keys won't fire a key typed event.
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(200,200);
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
System.out.println("from keyTyped: " + e.getKeyCode());
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("from keyPressed: " + e.getKeyCode());
}
#Override
public void keyReleased(KeyEvent e) {
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
If I want to do this.getInputMap() in my JFrame, this is impossible
Because a JFrame is NOT a JComponent.
You add Key Bindings to a JComponent. In this case you would add the Key Bindings to the "root pane" of the JFrame.
Read the section from the Swing tutorial on How to Use Root Panes for basic information.
I also showed you how to access the root pane in the link I provide above on Key Bindings.
Related
How do I make the Enter key trigger a JComboBox or JButton in a GUI rather than having to hit the Space key? I have an assortment of text fields and check boxes with buttons and combo boxes in between. I'd like to avoid having to switch between hitting space and enter and rather only have to hit enter for all components.
package koning.personal.dungeonsanddragons;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class test {
JFrame window = new JFrame("testGUI");
JPanel windowPanel = new JPanel();
public static JLabel labelSize;
public static JComboBox<String> comboSize;
public static JLabel labelButton;
public static JButton buttonButton;
public test () {
super();
labelSize = new JLabel("Monster Size:");
String[] sizeChoices = { "None", "Tiny", "Small", "Medium", "Large", "Huge", "Colossal"};
comboSize = new JComboBox<String>(sizeChoices);
comboSize.setToolTipText("The creature's size.");
labelButton = new JLabel("Button:");
buttonButton = new JButton();
windowPanel.setLayout(new FlowLayout());
windowPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
windowPanel.add(labelSize);
windowPanel.add(comboSize);
windowPanel.add(labelButton);
windowPanel.add(buttonButton);
windowPanel.setVisible(true);
window.setSize(500, 500);
window.setLayout(new FlowLayout());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
window.add(windowPanel);
comboSize.addActionListener(handler);
buttonButton.addActionListener(handler);
}
ActionHandler handler = new ActionHandler();
public class ActionHandler implements ActionListener {
public void actionPerformed(ActionEvent eventFocus){
if (eventFocus.getSource() == comboSize){
buttonButton.requestFocusInWindow();
}
if (eventFocus.getSource() == buttonButton){
comboSize.requestFocusInWindow();
}
}
}
#SuppressWarnings("unused")
public static void main(String[] args) {
test GUITest = new test();
}
}
You can add a KeyListener and execute doClick
JButton btn = new JButton();
btn.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER)
btn.doClick();
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
});
If the goal is to have something happen when the enter button is pressed (pressed once and something happens with all the components) then you can add a KeyListener to the JFrame:
JFrame frame = new JFrame("Examplpe");
//here you create and add the components to the frame
and then you can add a KeyListener:
frame.addKeyListener(new KeyListener(
#Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode == KeyEvent.VK_ENTER){//this is the if block I'm refering to in the following explanation
//do something with all the components
}
}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {}
}
and then when you press Enter, the code inside the if block will be executed.
Hope this helps :)
It's a very simple program, but for some reason when I debug it and set breakpoints at the keyPressed, keyReleased and keyTyped method, the program never stops there.
mainKeyListener = new KeyListener() {
public void keyPressed(KeyEvent e) {
System.out.println("KEY PRESSED");
repaint();
}
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
};
Here I add it to a JPanel, which is the exact size of the frame and the only object on it:
JPanel backgroundPanel = new JPanel();
backgroundPanel.setBounds(0,0, 400, 500);
backgroundPanel.addKeyListener(mainKeyListener);
backgroundPanel.setFocusable(true);
getContentPane().add(backgroundPanel);
Your problem is laying in focused element. I think that your panel lost the focus.
Note:
To fire keyboard events, a component must have the keyboard focus. It can be solved in many ways for your example you can use KeyboardFocusManager for example like this:
KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addKeyEventDispatcher(new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
if(focusManager.getFocusOwner()!=backgroundPanel){
focusManager.redispatchEvent(backgroundPanel,e);
return true;}
else return false;
}
});
Also try to use Key Bindings http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html
Hi this should work for you.
public class Gui extends JFrame
{
private JPanel backgroundPanel = new JPanel();
public Gui() throws HeadlessException
{
this.setLayout(new GridLayout(1,1));
setPanelProps();
backgroundPanel.addKeyListener(createListener());
this.add(backgroundPanel);
this.setVisible(true);
this.setSize(new Dimension(400,500));
}
public void setPanelProps(){
backgroundPanel.setBounds(0, 0, 400, 500);
backgroundPanel.setSize(new Dimension(400,500));
backgroundPanel.setFocusable(true);
backgroundPanel.setBackground(new Color(50,60,70));
}
public KeyListener createListener(){
return new KeyListener() {
#Override
public void keyTyped(KeyEvent e)
{
System.out.println("KEY TYPED");
}
public void keyPressed(KeyEvent e) {
System.out.println("KEY PRESSED");
repaint();
}
#Override
public void keyReleased(KeyEvent e)
{
System.out.println("KEY RELEASED");
}
};
}
}
public class GuiRun
{
public static void main(String[] args)
{
Gui gui = new Gui();
}
}
Yes, this question is already posted on JavaRanch but I do not understand them well.
I have JDialog which has MouseListener added as follows:
super.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
if (e.getSource() instanceof ConnectionTreeTooltip) {
System.out.println("mouse exited!!!!!!!!!!!!!!!!!!=" + e);
// hideTooltip();
}
}
#Override
public void mouseEntered(MouseEvent e) {
if (e.getSource() instanceof ConnectionTreeTooltip) {
System.out.println("mouse entered!!!!!!!!!!!!!!!!!!=" + e);
// hideTooltip();
}
}
});
ConnectionTreeTooltip is this jdialog.
The problem is that both these two methods are invoked whenever mouse enters or exits JDialog. They merely run together.
The code of my JDialog:
public class ConnectionTreeTooltip extends JDialog {
...........
public ConnectionTreeTooltip(ConnectionsTree connectionsTree) {
super(connectionsTree.getMainFrame(), "", false);
super.setUndecorated(true);
super.setFocusableWindowState(false);
.............
super.getContentPane().add(scrollPane);
super.pack();
}
connectionsTree.getMainFrame() returns instance of JFrame.
EDIT Here is full code :
public ConnectionTreeTooltip(ConnectionsTree connectionsTree) {
super(connectionsTree.getMainFrame(), "", false);
super.setUndecorated(true);
super.setFocusableWindowState(false);
this.connectionsTree = connectionsTree;
JPanel contentPane = (JPanel) super.getContentPane();
contentPane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.blue, Color.red));
tipLabel = new JLabel();
// by default, JLabel is not focusable.
tipLabel.setFocusable(true);
tipLabel.setBackground(Color.WHITE);
scrollPane = new JScrollPane(tipLabel) {
#Override
public Dimension getPreferredSize() {
return preferredSizeOfScrollPane;
}
};
scrollPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 1, 1));
super.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
if (e.getSource() instanceof ConnectionTreeTooltip) {
System.out.println("mouse exited!!!!!!!!!!!!!!!!!!=" + e);
// hideTooltip();
}
}
#Override
public void mouseEntered(MouseEvent e) {
if (e.getSource() instanceof ConnectionTreeTooltip) {
System.out.println("mouse entered!!!!!!!!!!!!!!!!!!=" + e);
// hideTooltip();
}
}
});
tipLabel.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
// tipLabel can key events only if it is visible and focused
if (e.getKeyCode() == 32) {
unFocusTipLabel();
}
}
});
super.getContentPane().add(scrollPane);
super.pack();
}
Why is that and what is wrong with my JDialog or my MouseListener?
Thank you!
In all likelihood your JDialog holds a component inside of it that steals the mouse listener from the dialog itself, and so when your mouse enters the dialog, the dialog senses the mouse entering, but then the mouse immediately enters the dialog's component (the JScrollPane perhaps), the mouselistener senses that you've left the dialog and have entered its child component.
For example, my SSCCE:
import java.awt.event.*;
import javax.swing.*;
public class MouseListenerTest {
public static void main(String[] args) {
final JFrame mainFrame = new JFrame("My Frame");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.add(new JPanel() {
{
add(new JButton(new AbstractAction("Show Dialog") {
#Override
public void actionPerformed(ActionEvent arg0) {
ConnectionTreeTooltip cttt = new ConnectionTreeTooltip(
mainFrame);
cttt.setVisible(true);
}
}));
}
});
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
}
class ConnectionTreeTooltip extends JDialog {
public ConnectionTreeTooltip(JFrame mainFrame) {
super(mainFrame, "", false);
setUndecorated(true);
setFocusableWindowState(false);
add(new JScrollPane(new JTextArea(20, 40)));
((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
pack();
addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
if (e.getSource() instanceof ConnectionTreeTooltip) {
System.out.println("mouse exited!!!!!!!!!!!!!!!!!!=" + e);
// hideTooltip();
}
}
#Override
public void mouseEntered(MouseEvent e) {
if (e.getSource() instanceof ConnectionTreeTooltip) {
System.out.println("mouse entered!!!!!!!!!!!!!!!!!!=" + e);
// hideTooltip();
}
}
});
}
}
now the tough part is to figure out how to use the GlassPane to get your Mouse enter/leaving information, but still allow the mouse events to be passed onto the dialog that's below the glass pane.
Edit
Yep the solution is to use the glass pane:
import java.awt.event.*;
import javax.swing.*;
public class MouseListenerTest {
public static void main(String[] args) {
final JFrame mainFrame = new JFrame("My Frame");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.add(new JPanel() {
{
add(new JButton(new AbstractAction("Show Dialog") {
#Override
public void actionPerformed(ActionEvent arg0) {
ConnectionTreeTooltip cttt = new ConnectionTreeTooltip(
mainFrame);
cttt.setVisible(true);
}
}));
}
});
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
}
class ConnectionTreeTooltip extends JDialog {
public ConnectionTreeTooltip(JFrame mainFrame) {
super(mainFrame, "", false);
setUndecorated(true);
setFocusableWindowState(false);
add(new JScrollPane(new JTextArea(20, 40)));
((JPanel) getContentPane()).setBorder(
BorderFactory.createEmptyBorder(4, 4, 4, 4));
pack();
JComponent glassPane = (JComponent) getGlassPane();
glassPane.setVisible(true);
glassPane.addMouseListener(new MyMouseAdapter());
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseExited(MouseEvent e) {
System.out.println("mouse exited");
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("mouse entered");
}
}
}
I solved my problem in better way than using GlassPane. GlassPane only added more troubles to me because I could not scroll JScrollPane which is under GlassPane and redispatching mouse event suggested in glasspane swing tutorial did not help at all because mouseListener on glasspane did not receive mouseDragged.
The solution is by using AWTEventListener. With AWTEventListener I can check for component event is on and event's ID. So my AWTEventListener checks if mouseEntered event occurred over JDialog and if so it is focused programmatically. And if mouseDragged event occurred over JScrollPane I scroll it programmatically. Finally if mouseExited event occurred on JDialog it is hidden.
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
MouseEvent me = (MouseEvent) event;
Component mouseComponent = me.getComponent();
if (mouseComponent == scrollPane) {
if (me.getID() == MouseEvent.MOUSE_DRAGGED) {
scrollPane.getViewport().setViewPosition(me.getPoint()); // scroll JScrollPane programmatically
}
} else if (mouseComponent == ConnectionTreeTooltip.this) {
if (me.getID() == MouseEvent.MOUSE_ENTERED)
focusTipLabel(); //focus JDialog(ConnectionTreeTooltip)
else if (me.getID() == MouseEvent.MOUSE_EXITED) {
hideTooltip(); //hide JDialog(ConnectionTreeTooltip)
}
}
}
}, AWTEvent.MOUSE_EVENT_MASK);
But this AWTEventListener works for mouseevents generated from any component in my main frame. And it does not always handle mouseExited event on JDialog.
Or a simpler alternative. Check the coordinates of the mouse on the mouseExited and only count as an exit if the mouse is really outside the control:
super.addMouseListener(new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
Point cursor = e.getPoint();
if ( (cursor.x < super.getX()) || (cursor.y < super.getY()) || (cursor.x > popup.getX()+super.getWidth()) || (cursor.y > super.getY()+super.getHeight()))
popup.setVisible(false);
}
});
I am trying to do something when one of the arrow keys are pressed using the KeyListener in my JPanel class. Here is my code:
public class TestPanel extends JPanel implements KeyListener{
public TestPanel(){
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left");
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
My main method adds a new instance of this panel to a frame and displays it. Do I need to add the keylistener to the JFrame? In my case, this would be difficult and inefficient, so I would like to make it work with this JPanel if possible. Anyone know what I am doing wrong?
EDIT: Key Bindings code that does not work either:
public class GamePanel extends JPanel implements ActionListener{
//Constructor
public GamePanel(){
setupKeyBinding();
this.setFocusable(true);
this.requestFocusInWindow();
}
private void setupKeyBinding() {
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inMap = getInputMap(condition);
ActionMap actMap = getActionMap();
inMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "Left");
actMap.put("Left", new leftAction());
}
private class leftAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
System.out.println("test");
}
}
public void actionPerformed(ActionEvent e) {
//some other game info
}
}
Can someone tell me why this doesnt work either? (my second action listener is for other stuff needed for my game)
If you search this problem, you'll see that it is asked and has been solved many times.
KeyListeners need to be on the focused component to work. One solution is to give your component the focus after first making it focusable.
Better by a long shot however is to use Key Bindings. Google the tutorial on this.
Please have a look at my answer to this question for more on this, including many of the gory details.
For reference, I've create an example using your approach; while it works, it also suggests a focus problem elsewhere in your code. Key Bindings avoid this, as shown here.
Addendum: Here's my working key binding.
private static class TestPanel extends JPanel {
private static final String LEFT = "Left";
private Action left = new AbstractAction(LEFT) {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(LEFT);
}
};
private static final String RIGHT = "Right";
private Action right = new AbstractAction(RIGHT) {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(RIGHT);
}
};
public TestPanel() {
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
this.getActionMap().put(LEFT, left);
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
this.getActionMap().put(RIGHT, right);
}
}
Original SSCCE:
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/16531380/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TestPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class TestPanel extends JPanel implements KeyListener {
public TestPanel() {
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left");
}
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
For receives key events on JPanel you must set focus:
setFocusable(true);
requestFocus();
the JPanel now has focus, so it receives key events
I had to do two things: I added comp.setFocusable(true); to the component comp that listens to key events, and I added comp.requestFocus(); to each action which caused comp to lose the focus.
I've got an interface with 2 JFormattedTextFields for which I need the values (not just the displayed text) to be identical. Ideally they should both be editable, with a change in one being mirrored in the other.
I started by just sharing a single Document between the two, but quickly ran into the problem that this only links the displayed text, not the underlying value. (Silly me!)
I haven't tried adding reciprocal PropertyChangeListeners for the "value" property because I would expect that to set up an infinite loop of modification.
Am I missing something? Is there some way to do this? Or am I stuck with only allowing users to edit one of the two and only having the value propagate in one direction?
Thank you!
I need the values (not just the displayed text) to be identical.
Ideally they should both be editable, with a change in one being
mirrored in the other.
use DocumentListener,
for example (only the one directions)
import java.awt.GridLayout;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class TextLabelMirror {
private JPanel mainPanel = new JPanel();
private JTextField field = new JTextField(20);
private JTextField field1 = new JTextField(20);
public TextLabelMirror() {
field.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
updateLabel(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
updateLabel(e);
}
private void updateLabel(DocumentEvent e) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
field1.setText(field.getText());
}
});
}
});
mainPanel.setLayout(new GridLayout(1, 0, 10, 0));
mainPanel.add(field);
mainPanel.add(field1);
}
public JComponent getComponent() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("TextLabelMirror");
frame.getContentPane().add(new TextLabelMirror().getComponent());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowUI();
}
});
}
}
You can use a key listener. You simply add a key listener to both fields using the below code. the reason you need the other events is it will throw errors unless you have them in the code.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CreateGrid
{
JFrame thisframe;
JFormattedTextField jFormattedTextField1, jFormattedTextField2;
public CreateGrid()
{
GridLayout thislayout = new GridLayout(0,2);
thisframe = new JFrame();
thisframe.setLayout(thislayout);
jFormattedTextField1 = new JFormattedTextField();
jFormattedTextField2 = new JFormattedTextField();
jFormattedTextField1.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
JFormattedTextField textField = (JFormattedTextField) e.getSource();
String text = textField.getText();
jFormattedTextField2.setText(text);
}
public void keyTyped(KeyEvent e)
{
}
public void keyPressed(KeyEvent e)
{
}
});
jFormattedTextField2.addKeyListener(new KeyAdapter()
{
public void keyReleased(KeyEvent e)
{
JFormattedTextField textField = (JFormattedTextField) e.getSource();
String text = textField.getText();
jFormattedTextField1.setText(text);
}
public void keyTyped(KeyEvent e)
{
}
public void keyPressed(KeyEvent e)
{
}
});
thisframe.add(jFormattedTextField1);
thisframe.add(jFormattedTextField2);
thisframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisframe.setVisible(true);
thisframe.pack();
}
public static void main(String args[])
{
new CreateGrid();
}
}
I have tested this out and it works perfectly what ever you type into one field will show up in the other as you type it.