Google Tag Manager

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

2020/05/02

Disable the JOptionPane OK button until text is entered in the JTextField

Code

JPanel panel2 = new JPanel(new GridLayout(2, 1));
JTextField field2 = new JTextField();
Border enabledBorder = field2.getBorder();
Insets i = enabledBorder.getBorderInsets(field2);
Border disabledBorder = BorderFactory.createCompoundBorder(
    BorderFactory.createLineBorder(Color.RED),
    BorderFactory.createEmptyBorder(i.top - 1, i.left - 1, i.bottom - 1, i.right - 1));
String disabledMessage = "Text is required to create ...";
JLabel label2 = new JLabel(" ");
label2.setForeground(Color.RED);
panel2.add(field2);
panel2.add(label2);
if (field2.getText().isEmpty()) {
  field2.setBorder(disabledBorder);
  label2.setText(disabledMessage);
}
field2.addHierarchyListener(e -> {
  Component c = e.getComponent();
  if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && c.isShowing()) {
    EventQueue.invokeLater(c::requestFocusInWindow);
  }
});
field2.getDocument().addDocumentListener(new DocumentListener() {
  private void update() {
    boolean verified = !field2.getText().isEmpty();
    JButton b = field2.getRootPane().getDefaultButton();
    if (verified) {
      b.setEnabled(true);
      field2.setBorder(enabledBorder);
      label2.setText(" ");
    } else {
      b.setEnabled(false);
      field2.setBorder(disabledBorder);
      label2.setText(disabledMessage);
    }
  }

  @Override public void insertUpdate(DocumentEvent e) {
    update();
  }

  @Override public void removeUpdate(DocumentEvent e) {
    update();
  }

  @Override public void changedUpdate(DocumentEvent e) {
    update();
  }
});
JButton button2 = new JButton("show");
button2.addActionListener(e -> {
  Component p2 = log.getRootPane();
  EventQueue.invokeLater(() -> {
    JButton b = field2.getRootPane().getDefaultButton();
    if (b != null && field2.getText().isEmpty()) {
      b.setEnabled(false);
    }
  });
  int ret = JOptionPane.showConfirmDialog(
      p2, panel2, "Input text", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
  if (ret == JOptionPane.OK_OPTION) {
    log.setText(field2.getText());
  }
});

References