I've started on a largish Java project (4000+ classes) with a complex Swing UI front-end and have had difficulty working out just which class is in play for a given visual component.
Glass pane to the rescue.
To help me out, I've written a small debugging glass pane based on a universal right-click handler found on Google similar to the example provided in the Swing documentation.
Use is simple:
JFrame frame = ...; DebugGlassPane.setDebugGlassPaneOn(frame);
Now when you hover the mouse over a component in the content pane, up pops a tooltip identifying the class and instance name. If you want to change the displayed information, edit createTipText(Component)
.
The complete class:
public class DebugGlassPane extends JComponent implements MouseListener, MouseMotionListener { private final JLayeredPane layered; public static void setDebugGlassPaneOn(final JFrame frame) { final Component glass = new DebugGlassPane(frame); // Must be in this order frame.setGlassPane(glass); glass.setVisible(true); } public DebugGlassPane(final JFrame frame) { layered = frame.getLayeredPane(); addMouseListener(this); addMouseMotionListener(this); } public void mouseMoved(final MouseEvent e) { setToolTipText(createTipText(getChildUnderMouse(e))); redispatchMouseEvent(e); } public void mouseDragged(final MouseEvent e) { redispatchMouseEvent(e); } public void mouseClicked(final MouseEvent e) { redispatchMouseEvent(e); } public void mouseEntered(final MouseEvent e) { redispatchMouseEvent(e); } public void mouseExited(final MouseEvent e) { redispatchMouseEvent(e); } public void mousePressed(final MouseEvent e) { redispatchMouseEvent(e); } public void mouseReleased(final MouseEvent e) { redispatchMouseEvent(e); } private String createTipText(final Component c) { return "<html>Class: <b>" + c.getClass().getName() + "</b><br>Name: <i>" + c.getName(); } private void redispatchMouseEvent(final MouseEvent e) { final Component component = getChildUnderMouse(e); // E.g., popup menus if (component == null) return; // redispatch the event component.dispatchEvent( SwingUtilities.convertMouseEvent(this, e, component)); } private Component getChildUnderMouse(final MouseEvent e) { // get the mouse click point relative to the content pane final Point containerPoint = SwingUtilities.convertPoint(this, e.getPoint(), layered); return SwingUtilities.getDeepestComponentAt(layered, containerPoint.x, containerPoint.y); } }
Surprisingly, I had a difficult time finding such a class already coded up somewhere. It is quite handy for exploring the UI.
UPDATE: An important fix (already incorporated in the code, above). Say you have a menu bar. The current code throws a NullPointerException
. The problem is that all the work is relative to the content pane, but a JFrame
can have visual space which recieves mouse events but is not part of the content.
The fix is simple: change getChildUnderMouse(MouseEvent)
to work with the component from frame.getLayeredPane()
instead of frame.getContentPane()
. Sun has a good explanatory diagram and description making this point clear.
No comments:
Post a Comment