• category: swing folder: EditInternalFrameTitle title: JInternalFrameにJPopupMenuを設定してタイトルを変更する tags: [JInternalFrame, JPopupMenu] author: aterai pubdate: 2021-08-30T02:48:24+09:00 description: JInternalFrameのタイトルをタイトルバーやアイコン化された状態のJDesktopIconからJPopupMenuを開いて変更します。 image: https://drive.google.com/uc?id=1OBg1GInat6Dbj4WK5tRYaSihXxU2E32R

概要

JInternalFrameのタイトルをタイトルバーやアイコン化された状態のJDesktopIconからJPopupMenuを開いて変更します。

サンプルコード

private static JInternalFrame createFrame(String t, int i) {
  JInternalFrame f = new JInternalFrame(t + i, true, true, true, true);
  f.setSize(200, 100);
  f.setLocation(5 + 40 * i, 5 + 50 * i);
  JPopupMenu popup = new InternalFramePopupMenu();
  f.setComponentPopupMenu(popup);
  // ((BasicInternalFrameUI) f.getUI()).getNorthPane().setComponentPopupMenu(popup);
  ((BasicInternalFrameUI) f.getUI()).getNorthPane().setInheritsPopupMenu(true);
  f.getDesktopIcon().setComponentPopupMenu(popup);
  EventQueue.invokeLater(() -> f.setVisible(true));
  return f;
}

class InternalFramePopupMenu extends JPopupMenu {
  protected InternalFramePopupMenu() {
    super();
    JTextField field = new JTextField(24); // { ... };
    String cmd = "Edit Title";
    add(cmd).addActionListener(e -> {
      Component c = getInternalFrame(getInvoker());
      if (c instanceof JInternalFrame) {
        JInternalFrame frame = (JInternalFrame) c;
        field.setText(frame.getTitle());
        Container p = frame.getDesktopPane();
        int ret = JOptionPane.showConfirmDialog(
            p, field, cmd, JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
        if (ret == JOptionPane.OK_OPTION) {
          renameInternalFrameTitle(frame, field.getText().trim());
        }
      }
    });
  }
  // ...
}

private static Component getInternalFrame(Component c) {
  Component f;
  if (c instanceof JInternalFrame.JDesktopIcon) {
    f = ((JInternalFrame.JDesktopIcon) c).getInternalFrame();
  } else if (c instanceof JInternalFrame) {
    f = c;
  } else { // if (c instanceof BasicInternalFrameTitlePane) {
    f = SwingUtilities.getAncestorOfClass(JInternalFrame.class, c);
  }
  return f;
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、JInternalFrameやそのアイコン化状態でのコンポーネントであるJInternalFrame.JDesktopIconsetComponentPopupMenu(...)メソッドでJPopupMenuを設定し、このJPopupMenuからJOptionPaneを開いてJInternalFrameのタイトルを変更しています。

  • Windows環境でJInternalFrameのタイトルバーを右クリックした場合の動作はLookAndFeelで異なる
    • NimbusLookAndFeel
      • デフォルトでは左端のタイトル(下向き三角)アイコンをクリックしたときに表示されるシステムポップアップメニューが表示される
      • JInternalFrameJPopupMenuを設定した場合、SynthInternalFrameTitlePaneに設定されたJPopupMenuを開く
      • SynthInternalFrameTitlePane#isInheritsPopupMenu() == trueなので親JInternalFrameJPopupMenuが開く
      • SynthInternalFrameTitlePaneから任意(デフォルトのシステムポップアップメニューを含む)のJPopupMenuを開き、Escキーや別コンポーネントをクリックしてポップアップ表示をキャンセルすると内部的にJInternalFrameが移動状態が継続して再度タイトルバーを左クリックするまでJInternalFrameのリサイズが不可能になる(リサイズカーソルのままJInternalFrameが移動する)
    • WindowsLookAndFeel
      • デフォルトではタイトルバーのシングル右クリックは無視され(システムメニューは表示されない)、左右どのマウスボタンのダブルクリックでもJInternalFrameの最大化、復元が実行される
      • デフォルトはWindowsInternalFrameTitlePane#isInheritsPopupMenu() == trueなので、WindowsInternalFrameTitlePane#setInheritsPopupMenu(true)などの設定で右クリックはポップアップ表示に変更可能(右マウスボタンのダブルクリックは無効になる)

参考リンク

コメント