• category: swing folder: SelectableToolTip title: JToolTipの文字列を選択・コピー可能にする tags: [JToolTip, JPopupMenu, JEditorPane] author: aterai pubdate: 2020-02-03T17:37:47+09:00 description: JToolTipの代わりにJPopupMenuを表示し、その内部に配置したコンポーネントのクリックや文字列の選択・コピーを可能にします。 image: https://drive.google.com/uc?id=1gSgkKvGUaTX9rESzzcCHyhNRREYr22cq hreflang:
       href: https://java-swing-tips.blogspot.com/2020/05/make-text-in-jtooltip-selectable-and.html
       lang: en

概要

JToolTipの代わりにJPopupMenuを表示し、その内部に配置したコンポーネントのクリックや文字列の選択・コピーを可能にします。

サンプルコード

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("<html>%s: <a href='%s'>%s</a>", title, url, url));
          popup.pack();
        });
  } else if (e.getEventType() == HyperlinkEvent.EventType.EXITED) {
    editorPane.setToolTipText(null);
  }
});
View in GitHub: Java, Kotlin

解説

  • JComponent#createToolTip()メソッドをオーバーライドしてJToolTipHierarchyListenerを追加
  • JToolTipが表示状態になったらそのJToolTipを親にしてJPopupMenuを表示
    • JToolTipJPopupMenuの背後に隠れている
    • JPopupMenuにはJMenuItemではなくJEditorPaneJCheckBoxを配置したJPanelを追加している
  • マウスカーソルを移動して親のJToolTipが非表示になってもJPopupMenuは閉じないので、内部のJCheckBoxをクリックしたりJEditorPaneの文字列を選択しCtrl-Cなどでコピー可能
    • 通常のJPopupMenuなので親JFrameなどをクリックしてフォーカスが移動すると非表示になる

参考リンク

コメント