Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations sizbut on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Detecting key pressed in Swing 1

Status
Not open for further replies.

SSJ

Programmer
Sep 26, 2002
54
PT
I'm building a Swing GUI and each of my JFrames will have a help file associated (html) that should be opened in another JFrame when the user hits the F2 button.

Problem is I can't detect key presses from the user by adding keyListeners to my JFrames ( I added keyListeners to my JFrame, but keyPress or keyReleased events never trigger when I press the buttons), so how can I detect that the user pressed F2 on my Frame? Is the only way adding keyListeners to every single component inside of it? Do I need to have another thread in each JFrame wich is sole purpose would be listening for this kind of events?
Or is there any nicer way to do it?

TIA
 
I think addKeyListener to every component is more simple way if there are not too many components in your jframe.
here is my code. keyTyped does not respond to function key.
Please look at the page for reference(search "F1" in the page).
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

class jf2 extends JFrame implements KeyListener{

static JFrame jfObj;

public jf2() {
super("function key");

getContentPane().setLayout(null);

JPanel jPan = new JPanel();
jPan.setBounds(0,0,200,200);
//jPan.setBackground(Color.white);

getContentPane().add(jPan);
JTextField jText = new JTextField("Hello");
jPan.add(jText);
jText.addKeyListener(this);

String data[] = {"one","two","three"};
JList dataList = new JList(data);
jPan.add(dataList);
dataList.addKeyListener(this);
addKeyListener(this); // add to JFrame jfObj
}

public static void main(String[] args) {

jfObj = new jf2();
jfObj.setSize(200, 200);
jfObj.setVisible(true);
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode()==KeyEvent.VK_F2)
System.out.println("f2 pressed");
}
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode()==KeyEvent.VK_F2)
System.out.println("f1 released");
}
public void keyTyped(KeyEvent e)
{
if (e.getKeyCode()==KeyEvent.VK_F2)
System.out.println("f1 typed");
}
}
 
Thanks for the reply, this is what I was afraid of, since in this case adding the listener to every component is almost impraticable in my case ( there are some complex GUIs involved and the app has a lot of Frames).
So isn't there a easy way to acomplish this?

How about using a Swing timer (with a time interval in the order of miliseconds) in my superclass with the sole purpose to monitor the desired function keypresses? Any comments on this? Would this not be advisable? Do you think it would be very resource consuming?

Any opinions on the matter are welcome
 
>>I added keyListeners to my JFrame, but keyPress or keyReleased events never trigger when I press the buttons)

I tried it and it works (adding KeyListeners to the JFrame), but you can have some problems with JTables.
 
hologram: It works? Can you exactly tell me what test did you make? Since if I have a JFrame with lets say a JButton, and a JTextField if the focus is on one of these components when I press the key, the keyPressed event isn't catched by the JFrame keyListener, to do it I need to add keyListeners to both JButton and JTextField and only in this case it will work. But if I just add the key Listener to the JFrame it won't.

Actually I'm probably moving to use Oracle Help For Java instead of this solution, but still in that case I will have a similar problem.
 
I just created a new testprogram with a "JFrame with lets say a JButton, and a JTextField"

[ PS : Are you sure you added the KeyListener to your frame ? frame.addKeyListener(this); ]

The code
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class FunctionKey implements KeyListener {

  private JTextField textField;
  private JButton button;
  private JLabel label;

  public FunctionKey() {
  }

  public static void main(String[] args) {
    FunctionKey functionKey = new FunctionKey();
    functionKey.doIt();
  }

  public void doIt() {
    JFrame frame = new JFrame("Test Function Key");
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    frame.addKeyListener(this);
    Container cp = frame.getContentPane();
    cp.setLayout(new FlowLayout());
    textField = new JTextField("TextField");
    button = new JButton("Button");
    button.addActionListener(new Controller());
    button.setActionCommand("Action");
    label = new JLabel("Label");
    cp.add(textField);
    cp.add(button);
    cp.add(label);
    frame.setSize(400,300);
    frame.setVisible(true);
  }

  public void keyPressed(KeyEvent e) {
    if (e.getKeyCode()==KeyEvent.VK_F2) {
       System.out.println("f2 pressed");
       System.out.println("Source=" + e.getSource().getClass());
    }
  }

  public void keyReleased(KeyEvent e) {
    if (e.getKeyCode()==KeyEvent.VK_F2) {
      System.out.println("f2 released");
      System.out.println("Source=" + e.getSource().getClass());
    }
  }

  public void keyTyped(KeyEvent e) {
    if (e.getKeyCode()==KeyEvent.VK_F2) {
      System.out.println("f2 typed");
      System.out.println("Source=" + e.getSource().getClass());
    }
  }

  private class Controller implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      String value = ((JButton)(e.getSource())).getActionCommand();
      System.out.println("Sending value " + value + " to the server ...");
    }
  }

}

The output (after pressing F2 when focus on textfield and then when focus on button
f2 pressed
Source=class javax.swing.JFrame
f2 released
Source=class javax.swing.JFrame
Sending value Action to the server ...
f2 pressed
Source=class javax.swing.JFrame
f2 released
Source=class javax.swing.JFrame
 
hologram: I tested your code (and that's exactly what I was doing in my case) and at first it wasn't working also. And I found out why, that code will only work on jdk1.3.1 for me (thats what you've used?), if I run it on jdk1.4.x it doesn't work, I need to add the keylistener manually to each the components like mentioned before.

Can you please confirm if it was jdk1.3.1 that you used to run your code?

I found it strange that the behaviour is so different in 1.4, maybe a bug? Or is this the way sun intends things should work now?

Thing is I can't move my project back to 1.3.1, so apparently I'll need to manually add key listeners to all components in my frame.

 
SSJ,

You are right, I ran my code with jdk1.3.1 and it works.
Then I switched to jdk1.4.2 and it doesn't work anymore.

I thought that maybe in jdk1.4.2 there are already KeyListeners attached to the JFrame or to the JTextField (intercepting the keypress), but this doesn't seem to be the case.

I think that is has to do with the focus : see
KeyListeners installed on Components will no longer see KeyEvents that map to focus traversal operations, and Component.handleEvent() will no longer be invoked for such events. Previously, AWT Components saw these events and had an opportunity to consume them before AWT initiated focus traversal. Code that requires this functionality should instead disable focus traversal keys on its Components and handle focus traversal itself. Alternately, the code can use an AWTEventListener or KeyEventDispatcher to pre-listen to all KeyEvents
 
hologram, it seems that you found the trick there. I actually managed to work around my problem by overriding the add method of JPanel and adding the keylisteners there.
It gave me some work to do, but now it's all good and for what I see it seems to be the easier solution.
But still I'll give a look at the focus traversal and those Events mentioned to see how it works now.

Thanks for digging that info out :)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top