Working on a help system, I'd like each component to offer some help when the the mouse is over it and the "?" key is pressed. Sort of like tooltips, except with much more extensive help - essentially a little web browser is intended to pop up and display text, images or more.
What I'm finding is that no matter where the mouse is, the input always goes to the same KeyListener. Is there only supposed to be one active at a time?
For what it's worth, this is the now-working version - thanks for suggestions!
/** * Main class JavaHelp wants to support a help function so that when * the user types F1 above a component, it creates a popup explaining * the component. * The full version is intended to be a big brother to tooltips, invoking * an HTML display with clickable links, embedded images, and the like. */ import javax.swing.*; import javax.swing.border.Border; import java.awt.*; import java.awt.event.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; class Respond2Key extends AbstractAction { Component jrp; // Contract consructor public Respond2Key( String text) { super( text ); } // Constructor that makes sure it gets done right public Respond2Key( String text, Component jrpIn) { super( text ); System.out.println( "creating Respond2Key with component " + jrpIn .toString () ); jrp = jrpIn; } public void setJrp( Component j) { jrp = j; } // Functionality: what is the response to a key public void actionPerformed(ActionEvent e) { // use MouseInfo to get position, convert to pane coords, lookup component Point sloc = MouseInfo.getPointerInfo().getLocation(); SwingUtilities.convertPointFromScreen( sloc, (Component) jrp ); Component c = jrp.getComponentAt( sloc ); System.out.printf( "Mouse at %5.2f,%5.2f Component under mouse is %s\n", sloc.getX(), sloc.getY(), c.toString() ); } } //---------------------------------------------------------------- // The main class //---------------------------------------------------------------- public class JavaHelp extends JFrame { // The object constructor public JavaHelp() { // Start construction super( "Help System" ); this.setSize( 640, 480 ); Container contents = getContentPane(); contents.setLayout( new FlowLayout() ); JButton b1 = butt( "button1", 64, 48 ); JButton b2 = butt( "button2", 96, 48 ); JButton b3 = butt( "button3", 128, 48 ); JPanel p1 = pane( "hello", 100, 100 ); JPanel p2 = pane( "world", 200, 100 ); contents.add( b1 ); contents.add( p1 ); contents.add( b2 ); contents.add( p2 ); contents.add( b3 ); JRootPane jrp = this.getRootPane(); jrp.getInputMap( jrp.WHEN_IN_FOCUSED_WINDOW) .put( KeyStroke.getKeyStroke( "F1" ), "helpAction" ); jrp.getActionMap().put( "helpAction", new Respond2Key("frame",(Component)contents) ); this.setVisible( true ); this.requestFocus(); this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); } // Inner classes for instantiating and listening to button, and panel. class ButtonListener implements ActionListener { private String label = null; public void setLabel(String s) {label = s;} public void actionPerformed(ActionEvent e) { System.out.printf( "Dealing with event labeled %s source %s\n\n", label, e.getSource().toString() ); } } // def butt( from, name, w, h) = new Jbutton (...) protected JButton butt( String s, int w, int h) { JButton b = new JButton( s ); b.setSize( w, h ); ButtonListener oj = new ButtonListener(); oj.setLabel( s ); b.addActionListener( oj ); return (b); } // def pane = new Jpanel(...) protected JPanel pane(String name, int w, int h) { JPanel p = new JPanel(); p.setMinimumSize( new Dimension( w, h ) ); p.add( new Label( name ) ); p.setBackground( Color.black ); p.setForeground( Color.red ); return (p); } //-------------------------------- public static void main(String[] args) { JavaHelp jh = new JavaHelp(); } }
the input always goes to the same KeyListener.
A KeyEvent is always dispatched to the component with focus, the mouse location has nothing to do with how the key event is generated.
Instead of using a KeyListener, you should be using Key Bindings
. When you using Key Bindings you can invoke an Action whenever a KeyStroke is generated by adding the binding to the root pane of the JFrame. Read the section from the Swing tutorial on Key Bindings for more information.
Now in the Action that you create to listen for the "?" KeyStroke you can then:
MouseInfo
class to get the current mouse location.SwingUtilities.convertPointFromScreen(...)
to convert the mouse point to be relative to the root paneConatiner.getComponentAt(...)
to get the actual component the mouse is over