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