Google Tag Manager

Showing posts with label JToolTip. Show all posts
Showing posts with label JToolTip. Show all posts

2024/12/31

Create a multi-line JToolTip using JTextArea's automatic line wrapping

Code

class LineWrapToolTip extends JToolTip {
  private static final double JAVA17 = 17.0;
  private static final JLabel MEASURER = new JLabel(" ");
  private static final int TIP_WIDTH = 200;
  private final JTextArea textArea = new JTextArea(0, 20);

  protected LineWrapToolTip() {
    super();
    textArea.setLineWrap(true);
    textArea.setWrapStyleWord(true);
    textArea.setOpaque(true);
    // textArea.setColumns(20);
    LookAndFeel.installColorsAndFont(
        textArea, "ToolTip.background", "ToolTip.foreground", "ToolTip.font");
    setLayout(new BorderLayout());
    add(textArea);
  }

  @Override public final void setLayout(LayoutManager mgr) {
    super.setLayout(mgr);
  }

  @Override public final Component add(Component comp) {
    return super.add(comp);
  }

  @Override public Dimension getPreferredSize() {
    Dimension d = getLayout().preferredLayoutSize(this);
    Dimension dim;
    String version = System.getProperty("java.specification.version");
    if (Double.parseDouble(version) >= JAVA17) {
      dim = getTextAreaSize17(d);
    } else {
      dim = getTextAreaSize8(d);
    }
    return dim;
  }

  private Dimension getTextAreaSize8(Dimension d) {
    Font font = textArea.getFont();
    MEASURER.setFont(font);
    MEASURER.setText(textArea.getText());
    Insets i = getInsets();
    int pad = getTextAreaPaddingWidth(i);
    // d.width = Math.min(d.width, MEASURER.getPreferredSize().width + pad);
    d.width = Math.min(TIP_WIDTH, MEASURER.getPreferredSize().width + pad);

    // JDK-8226513 JEditorPane is shown with incorrect size - Java Bug System
    // https://bugs.openjdk.org/browse/JDK-8226513
    AttributedString as = new AttributedString(textArea.getText());
    as.addAttribute(TextAttribute.FONT, font);
    AttributedCharacterIterator aci = as.getIterator();
    FontMetrics fm = textArea.getFontMetrics(font);
    FontRenderContext frc = fm.getFontRenderContext();
    LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
    float y = 0f;
    while (lbm.getPosition() < aci.getEndIndex()) {
      TextLayout tl = lbm.nextLayout(TIP_WIDTH);
      y += tl.getDescent() + tl.getLeading() + tl.getAscent();
    }
    d.height = (int) y + getTextAreaPaddingHeight(i);
    return d;
  }

  private Dimension getTextAreaSize17(Dimension d) {
    MEASURER.setFont(textArea.getFont());
    MEASURER.setText(textArea.getText());
    int pad = getTextAreaPaddingWidth(getInsets());
    d.width = Math.min(d.width, MEASURER.getPreferredSize().width + pad);
    return d;
  }

  private int getTextAreaPaddingWidth(Insets i) {
    // @see BasicTextUI.java
    // margin required to show caret in the rightmost position
    int caretMargin = -1;
    Object property = UIManager.get("Caret.width");
    if (property instanceof Number) {
      caretMargin = ((Number) property).intValue();
    }
    property = textArea.getClientProperty("caretWidth");
    if (property instanceof Number) {
      caretMargin = ((Number) property).intValue();
    }
    if (caretMargin < 0) {
      caretMargin = 1;
    }
    Insets ti = textArea.getInsets();
    return i.left + i.right + ti.left + ti.right + caretMargin;
    // Insets tm = textArea.getMargin();
    // return i.left + i.right + ti.left + ti.right + tm.left + tm.right;
  }

  private int getTextAreaPaddingHeight(Insets i) {
    Insets ti = textArea.getInsets();
    return i.top + i.bottom + ti.top + ti.bottom;
  }

  @Override public void setTipText(String tipText) {
    String oldValue = textArea.getText();
    textArea.setText(tipText);
    firePropertyChange("tiptext", oldValue, tipText);
    if (!Objects.equals(oldValue, tipText)) {
      revalidate();
      repaint();
    }
  }

  @Override public String getTipText() {
    return Optional.ofNullable(textArea).map(JTextArea::getText).orElse(null);
  }
}

References

2023/04/30

Change the tooltip of a tab in the JTabbedPane to a speech balloon shape, depending on the position of the tab.

Code

class BalloonToolTip extends JToolTip {
  private static final int SIZE = 4;
  private static final double ARC = 4d;
  private transient HierarchyListener listener;
  private transient Shape shape;

  @Override public void updateUI() {
    removeHierarchyListener(listener);
    super.updateUI();
    setLayout(new BorderLayout());
    listener = e -&gt; {
      Component c = e.getComponent();
      if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0
            &amp;&amp; c.isShowing()) {
        Optional.ofNullable(SwingUtilities.getWindowAncestor(c))
            .filter(w -&gt; w.getType() == Window.Type.POPUP)
            .ifPresent(w -&gt; w.setBackground(new Color(0x0, true)));
      }
    };
    addHierarchyListener(listener);
    setOpaque(false);
    setBorder(BorderFactory.createEmptyBorder(SIZE, SIZE, SIZE, SIZE));
  }

  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.width += SIZE;
    d.height += SIZE;
    return d;
  }

  @Override protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(getBackground());
    g2.fill(shape);
    g2.setPaint(getForeground());
    g2.draw(shape);
    g2.dispose();
    // super.paintComponent(g);
  }

  public void updateBalloonShape(int placement) {
    Insets i = getInsets();
    Dimension d = getPreferredSize();
    Path2D tail = new Path2D.Double();
    double w = d.getWidth() - i.left - i.right - 1d;
    double h = d.getHeight() - i.top - i.bottom - 1d;
    double cx = w / 2d;
    double cy = h / 2d;
    switch (placement) {
      case SwingConstants.LEFT:
        tail.moveTo(0, cy - SIZE);
        tail.lineTo(-SIZE, cy);
        tail.lineTo(0, cy + SIZE);
        break;
      case SwingConstants.RIGHT:
        tail.moveTo(w, cy - SIZE);
        tail.lineTo(w + SIZE, cy);
        tail.lineTo(w, cy + SIZE);
        break;
      case SwingConstants.BOTTOM:
        tail.moveTo(cx - SIZE, h);
        tail.lineTo(cx, h + SIZE);
        tail.lineTo(cx + SIZE, h);
        break;
      default: // case SwingConstants.TOP:
        tail.moveTo(cx - SIZE, 0);
        tail.lineTo(cx, -SIZE);
        tail.lineTo(cx + SIZE, 0);
    }
    Area area = new Area(new RoundRectangle2D.Double(0, 0, w, h, ARC, ARC));
    area.add(new Area(tail));
    AffineTransform at = AffineTransform.getTranslateInstance(i.left, i.top);
    shape = at.createTransformedShape(area);
  }
}

JTabbedPane tabs = new JTabbedPane(
    SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT) {
  private transient BalloonToolTip tip;
  private final JLabel label = new JLabel(" ", CENTER);

  @Override public Point getToolTipLocation(MouseEvent e) {
    int idx = indexAtLocation(e.getX(), e.getY());
    String txt = idx &gt;= 0 ? getToolTipTextAt(idx) : null;
    return Optional.ofNullable(txt).map(toolTipText -&gt; {
      JToolTip tips = createToolTip();
      tips.setTipText(toolTipText);
      label.setText(toolTipText);
      if (tips instanceof BalloonToolTip) {
        ((BalloonToolTip) tips).updateBalloonShape(getTabPlacement());
      }
      return getToolTipPoint(
          getBoundsAt(idx), tips.getPreferredSize());
    }).orElse(null);
  }

  private Point getToolTipPoint(Rectangle r, Dimension d) {
    double dx;
    double dy;
    switch (getTabPlacement()) {
      case LEFT:
        dx = r.getMaxX();
        dy = r.getCenterY() - d.getHeight() / 2d;
        break;
      case RIGHT:
        dx = r.getMinX() - d.width;
        dy = r.getCenterY() - d.getHeight() / 2d;
        break;
      case BOTTOM:
        dx = r.getCenterX() - d.getWidth() / 2d;
        dy = r.getMinY() - d.height;
        break;
      default: // case TOP:
        dx = r.getCenterX() - d.getWidth() / 2d;
        dy = r.getMaxY();
    }
    return new Point((int) (dx + .5), (int) (dy + .5));
  }

  @Override public JToolTip createToolTip() {
    if (tip == null) {
      tip = new BalloonToolTip();
      LookAndFeel.installColorsAndFont(
          label,
          "ToolTip.background",
          "ToolTip.foreground",
          "ToolTip.font");
      tip.add(label);
      tip.updateBalloonShape(getTabPlacement());
      tip.setComponent(this);
    }
    return tip;
  }

  @Override public void updateUI() {
    tip = null;
    super.updateUI();
  }
};

References

2022/01/31

Fix the JToolTip display of JList cells to correspond to after mouse wheel rotation

Code

JList<String> list1 = new JList<String>(model) {
  @Override public void updateUI() {
    super.updateUI();
    setCellRenderer(new TooltipListCellRenderer<>());
  }
};
JScrollPane scroll1 = new JScrollPane(list1);
scroll1.addMouseWheelListener(e -> {
  JScrollPane scrollPane = (JScrollPane) e.getComponent();
  Component view = scrollPane.getViewport().getView();
  MouseEvent event = SwingUtilities.convertMouseEvent(scrollPane, e, view);
  ToolTipManager.sharedInstance().mouseMoved(event);
});

References

2021/11/30

Add a vertical JSlider in the JPopupMenu and display it at the top of the JToggleButton

Code

JPopupMenu popup = new JPopupMenu();
popup.setLayout(new BorderLayout());
popup.addMouseWheelListener(InputEvent::consume);

UIManager.put("Slider.paintValue", Boolean.TRUE);
UIManager.put("Slider.focus", UIManager.get("Slider.background"));
JSlider slider = new JSlider(SwingConstants.VERTICAL, 0, 100, 80);
slider.addMouseWheelListener(e -> {
  JSlider s = (JSlider) e.getComponent();
  if (s.isEnabled()) {
    BoundedRangeModel m = s.getModel();
    m.setValue(m.getValue() - e.getWheelRotation() * 2);
  }
  e.consume();
});
popup.add(slider);

JToggleButton button = new JToggleButton("🔊") {
  @Override public JToolTip createToolTip() {
    JToolTip tip = super.createToolTip();
    tip.addHierarchyListener(e -> {
      long flg = e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED;
      if (flg != 0 && e.getComponent().isShowing()) {
        Dimension d = popup.getPreferredSize();
        popup.show(this, (getWidth() - d.width) / 2, -d.height);
      }
    });
    return tip;
  }

  @Override public Point getToolTipLocation(MouseEvent e) {
    return new Point(getWidth() / 2, -getHeight());
  }

  @Override public void setEnabled(boolean b) {
    super.setEnabled(b);
    setText(b ? "🔊" : "🔇");
  }
};
button.setToolTipText("");
button.addMouseListener(new MouseAdapter() {
  @Override public void mousePressed(MouseEvent e) {
    if (!button.isEnabled()) {
      slider.setValue(80);
      button.setEnabled(true);
    }
    Component b = (Component) e.getSource();
    Dimension d = popup.getPreferredSize();
    popup.show(b, (b.getWidth() - d.width) / 2, -d.height);
  }

  @Override public void mouseEntered(MouseEvent e) {
    if (!popup.isVisible()) {
      ToolTipManager.sharedInstance().setEnabled(true);
    }
  }

  @Override public void mouseExited(MouseEvent e) {
    if (!popup.isVisible()) {
      ToolTipManager.sharedInstance().setEnabled(true);
    }
  }
});
popup.addPopupMenuListener(new PopupMenuListener() {
  @Override public void popupMenuCanceled(PopupMenuEvent e) {
    /* not needed */
  }

  @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
    EventQueue.invokeLater(() -> ToolTipManager.sharedInstance().setEnabled(false));
  }

  @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
    button.setSelected(false);
  }
});

References

2020/05/31

Make text in a JToolTip selectable and copyable

Code

JEditorPane hint = new JEditorPane();
hint.setEditorKit(new HTMLEditorKit());
hint.setEditable(false);
hint.setOpaque(false);

JCheckBox check = new JCheckBox();
check.setOpaque(false);

JPanel panel = new JPanel(new BorderLayout());
panel.add(hint);
panel.add(check, BorderLayout.EAST);

JPopupMenu popup = new JPopupMenu();
popup.add(new JScrollPane(panel));
popup.setBorder(BorderFactory.createEmptyBorder());

JEditorPane editor = new JEditorPane() {
  @Override public JToolTip createToolTip() {
    JToolTip tip = super.createToolTip();
    tip.addHierarchyListener(e -> {
      if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0
            && e.getComponent().isShowing()) {
        panel.setBackground(tip.getBackground());
        popup.show(tip, 0, 0);
      }
    });
    return tip;
  }
};
editor.setEditorKit(new HTMLEditorKit());
editor.setText(HTML_TEXT);
editor.setEditable(false);
editor.addHyperlinkListener(e -> {
  JEditorPane editorPane = (JEditorPane) e.getSource();
  if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
    JOptionPane.showMessageDialog(editorPane, "You click the link with the URL " + e.getURL());
  } else if (e.getEventType() == HyperlinkEvent.EventType.ENTERED) {
    editorPane.setToolTipText("");
    Optional.ofNullable(e.getSourceElement())
        .map(elem -> (AttributeSet) elem.getAttributes().getAttribute(HTML.Tag.A))
        .ifPresent(attr -> {
          String title = Objects.toString(attr.getAttribute(HTML.Attribute.TITLE));
          String url = Objects.toString(e.getURL());
          // String url = Objects.toString(attr.getAttribute(HTML.Attribute.HREF));
          hint.setText(String.format("%s: %s", title, url, url));
          popup.pack();
        });
  } else if (e.getEventType() == HyperlinkEvent.EventType.EXITED) {
    editorPane.setToolTipText(null);
  }
});

  • Override JComponent#createToolTip() method to add HierarchyListener to JToolTip
  • Show JPopupMenu with JToolTip as parent when JToolTip is visible
    • JToolTip hides behind JPopupMenu
    • JPopupMenu adds a JPanel with a JEditorPane and a JCheckBox instead of a JMenuItem
  • Hiding the parent JToolTip with the mouse cursor does not close the JPopupMenu, so you can click the internal JCheckBox or select the text in the JEditorPane and copy it with Ctrl-C, etc
    • It is a normal JPopupMenu, so it is hidden when the focus is moved by clicking on the parent JFrame etc

References

2019/06/28

Make JToolTip translucent, and change its shape and display position

Code

class BalloonToolTip extends JToolTip {
  private static final int TRI_HEIGHT = 4;
  private HierarchyListener listener;

  @Override public void updateUI() {
    removeHierarchyListener(listener);
    super.updateUI();
    listener = e -> {
      Component c = e.getComponent();
      if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0
          && c.isShowing()) {
        Optional.ofNullable(SwingUtilities.getRoot(c))
           .filter(JWindow.class::isInstance).map(JWindow.class::cast)
           .ifPresent(w -> w.setBackground(new Color(0x0, true)));
      }
    };
    addHierarchyListener(listener);
    setOpaque(false);
    setForeground(Color.WHITE);
    setBackground(new Color(0xC8_00_00_00, true));
    setBorder(BorderFactory.createEmptyBorder(5, 5, 5 + TRI_HEIGHT, 5));
  }

  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.height = 32;
    return d;
  }

  @Override protected void paintComponent(Graphics g) {
    Shape s = makeBalloonShape();
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(getBackground());
    g2.fill(s);
    g2.dispose();
    super.paintComponent(g);
  }

  private Shape makeBalloonShape() {
    int w = getWidth() - 1;
    int h = getHeight() - TRI_HEIGHT - 1;
    int r = 10;
    int cx = getWidth() / 2;
    Polygon triangle = new Polygon();
    triangle.addPoint(cx - TRI_HEIGHT, h);
    triangle.addPoint(cx, h + TRI_HEIGHT);
    triangle.addPoint(cx + TRI_HEIGHT, h);
    Area area = new Area(new RoundRectangle2D.Float(0, 0, w, h, r, r));
    area.add(new Area(triangle));
    return area;
  }
}

// ...
@Override public String getToolTipText(MouseEvent e) {
  Point p = e.getPoint();
  int idx = locationToIndex(p);
  Rectangle rect = getCellBounds(idx, idx);
  if (idx < 0 || !rect.contains(p.x, p.y)) {
    return null;
  }
  Contribution value = getModel().getElementAt(idx);
  String act = value.activity == 0 ? "No" : Objects.toString(value.activity);
  return "<html>" + act + " contribution <span style='color:#C8C8C8'> on "
      + value.date.toString();
}

@Override public Point getToolTipLocation(MouseEvent e) {
  Point p = e.getPoint();
  int i = locationToIndex(p);
  Rectangle rect = getCellBounds(i, i);

  String toolTipText = getToolTipText(e);
  if (Objects.nonNull(toolTipText)) {
    JToolTip tip = createToolTip();
    tip.setTipText(toolTipText);
    Dimension d = tip.getPreferredSize();
    int gap = 2;
    return new Point((int) (rect.getCenterX() - d.getWidth() / 2d),
                     rect.y - d.height - gap);
  }
  return null;
}

@Override public JToolTip createToolTip() {
  if (tip == null) {
    tip = new BalloonToolTip();
    tip.setComponent(this);
  }
  return tip;
}

References

2016/12/27

Change the shape of JToolTip to balloon

Code

class BalloonToolTip extends JToolTip {
  private HierarchyListener listener;
  @Override public void updateUI() {
    removeHierarchyListener(listener);
    super.updateUI();
    listener = e -> {
      Component c = e.getComponent();
      boolean b = (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0;
      if (b && c.isShowing()) {
        Window w = SwingUtilities.getWindowAncestor(c);
        if (w != null && w.getType() == Window.Type.POPUP) {
          // Popup$HeavyWeightWindow
          w.setBackground(new Color(0x0, true));
        }
      }
    };
    addHierarchyListener(listener);
    setOpaque(false);
    setBorder(BorderFactory.createEmptyBorder(8, 5, 0, 5));
  }

  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.height = 28;
    return d;
  }

  @Override public void paintComponent(Graphics g) {
    Shape s = makeBalloonShape();
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(getBackground());
    g2.fill(s);
    g2.setColor(getForeground());
    g2.draw(s);
    g2.dispose();
    super.paintComponent(g);
  }

  private Shape makeBalloonShape() {
    Insets i = getInsets();
    int w = getWidth() - 1;
    int h = getHeight() - 1;
    int v = i.top / 2;
    Polygon triangle = new Polygon();
    triangle.addPoint(i.left + v + v, 0);
    triangle.addPoint(i.left + v, v);
    triangle.addPoint(i.left + v + v + v, v);
    Area area = new Area(new RoundRectangle2D.Float(
        0, v, w, h - i.bottom - v, i.top, i.top));
    area.add(new Area(triangle));
    return area;
  }
}

//...
JList<String> list = new JList<String>(model) {
  @Override public JToolTip createToolTip() {
    JToolTip tip = new BalloonToolTip();
    tip.setComponent(this);
    return tip;
  }
};

References

2015/12/01

Show JToolTip for Icons placed in the cell of the JTable

Code

JTable table = new JTable(model) {
  @Override public String getToolTipText(MouseEvent e) {
    Point pt = e.getPoint();
    int vrow = rowAtPoint(pt);
    int vcol = columnAtPoint(pt);
    int mcol = convertColumnIndexToModel(vcol);
    if (mcol == 1) {
      TableCellRenderer tcr = getCellRenderer(vrow, vcol);
      Component c = prepareRenderer(tcr, vrow, vcol);
      if (c instanceof JPanel) {
        Rectangle r = getCellRect(vrow, vcol, true);
        c.setBounds(r);
        c.doLayout();
        pt.translate(-r.x, -r.y);
        Component l = SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y);
        if (l instanceof JLabel) {
          ImageIcon icon = (ImageIcon) ((JLabel) l).getIcon();
          return icon.getDescription();
        }
      }
    }
    return super.getToolTipText(e);
  }
};

class ListIconRenderer implements TableCellRenderer {
  private final JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));

  @Override public Component getTableCellRendererComponent(
      JTable table, Object value,
      boolean isSelected, boolean hasFocus, int row, int column) {
    p.removeAll();
    if (isSelected) {
      p.setOpaque(true);
      p.setBackground(table.getSelectionBackground());
    } else {
      p.setOpaque(false);
    }
    if (value instanceof List<?>) {
      for (Object o : (List<?>) value) {
        if (o instanceof Icon) {
          Icon icon = (Icon) o;
          JLabel label = new JLabel(icon);
          label.setToolTipText(icon.toString());
          p.add(label);
        }
      }
    }
    return p;
  }
}

References

2015/10/30

Display tooltip while dragging JSlider thumb

Code

class SliderPopupListener extends MouseAdapter {
  private final JWindow toolTip = new JWindow();
  private final JLabel label = new JLabel("", SwingConstants.CENTER);
  private final Dimension size = new Dimension(30, 20);
  private int prevValue = -1;

  public SliderPopupListener() {
    label.setOpaque(false);
    label.setBackground(UIManager.getColor("ToolTip.background"));
    label.setBorder(UIManager.getBorder("ToolTip.border"));
    toolTip.add(label);
    toolTip.setSize(size);
  }

  protected void updateToolTip(MouseEvent me) {
    JSlider slider = (JSlider) me.getSource();
    int intValue = (int) slider.getValue();
    if (prevValue != intValue) {
      label.setText(String.format("%03d", slider.getValue()));
      Point pt = me.getPoint();
      pt.y = -size.height;
      SwingUtilities.convertPointToScreen(pt, (Component) me.getSource());
      pt.translate(-size.width / 2, 0);
      toolTip.setLocation(pt);
    }
    prevValue = intValue;
  }

  @Override public void mouseDragged(MouseEvent me) {
    updateToolTip(me);
  }

  @Override public void mousePressed(MouseEvent me) {
    toolTip.setVisible(true);
    updateToolTip(me);
  }

  @Override public void mouseReleased(MouseEvent me) {
    toolTip.setVisible(false);
  }
}

References

2008/10/20

Modal Internal Frame

Code

// menuItem.setMnemonic(KeyEvent.VK_1);
class ModalInternalFrameAction1 extends AbstractAction {
  public ModalInternalFrameAction1(String label) {
    super(label);
  }

  @Override public void actionPerformed(ActionEvent e) {
    setJMenuEnabled(false);
    JOptionPane.showInternalMessageDialog(
      desktop, "information", "modal1", JOptionPane.INFORMATION_MESSAGE);
    setJMenuEnabled(true);
  }
}

// menuItem.setMnemonic(KeyEvent.VK_2);
class ModalInternalFrameAction2 extends AbstractAction {
  private final JPanel glass = new MyGlassPane();
  public ModalInternalFrameAction2(String label) {
    super(label);
    Rectangle screen = frame.getGraphicsConfiguration().getBounds();
    glass.setBorder(BorderFactory.createEmptyBorder());
    glass.setLocation(0, 0);
    glass.setSize(screen.width, screen.height);
    glass.setOpaque(false);
    glass.setVisible(false);
    desktop.add(glass, JLayeredPane.MODAL_LAYER);
  }

  @Override public void actionPerformed(ActionEvent e) {
    setJMenuEnabled(false);
    glass.setVisible(true);
    JOptionPane.showInternalMessageDialog(
      desktop, "information", "modal2", JOptionPane.INFORMATION_MESSAGE);
    glass.setVisible(false);
    setJMenuEnabled(true);
  }
}

// menuItem.setMnemonic(KeyEvent.VK_3);
// Creating Modal Internal Frames -- Approach 1 and Approach 2
// http://web.archive.org/web/20090803142839/http://java.sun.com/developer/JDCTechTips/2001/tt1220.html
class ModalInternalFrameAction3 extends AbstractAction {
  private final JPanel glass = new PrintGlassPane();
  public ModalInternalFrameAction3(String label) {
    super(label);
    glass.setVisible(false);
  }

  @Override public void actionPerformed(ActionEvent e) {
    JOptionPane optionPane = new JOptionPane();
    JInternalFrame modal = optionPane.createInternalFrame(desktop, "modal3");
    optionPane.setMessage("Hello, World");
    optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
    removeSystemMenuListener(modal);
    modal.addInternalFrameListener(new InternalFrameAdapter() {
      @Override public void internalFrameClosed(InternalFrameEvent e) {
        glass.removeAll();
        glass.setVisible(false);
      }
    });
    glass.add(modal);
    modal.pack();
    getRootPane().setGlassPane(glass);
    glass.setVisible(true);
    modal.setVisible(true);
  }
}

References