概要

JInternalFrameのタイトルバーをマウスの右ボタンでダブルクリックしても最大化しないよう設定します。

サンプルコード

class DesktopLayerUI extends LayerUI<JDesktopPane> {
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
    }
  }

  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }

  @Override protected void processMouseEvent(MouseEvent e, JLayer<? extends JDesktopPane> l) {
    if (SwingUtilities.isRightMouseButton(e) && e.getClickCount() >= 2) {
      Component c = e.getComponent();
      Container p = SwingUtilities.getAncestorOfClass(BasicInternalFrameTitlePane.class, c);
      int id = e.getID();
      boolean b1 = c instanceof BasicInternalFrameTitlePane || p instanceof BasicInternalFrameTitlePane;
      boolean b2 = c instanceof JInternalFrame.JDesktopIcon && id == MouseEvent.MOUSE_PRESSED;
      if ((b1 && id == MouseEvent.MOUSE_CLICKED) || b2) {
        e.consume();
      }
    }
  }

  @Override protected void processMouseMotionEvent(MouseEvent e, JLayer<? extends JDesktopPane> l) {
    boolean b = e.getComponent() instanceof JInternalFrame;
    boolean isRight = SwingUtilities.isRightMouseButton(e);
    if (b && isRight && e.getID() == MouseEvent.MOUSE_DRAGGED) {
      e.consume();
    }
  }
}
View in GitHub: Java, Kotlin

解説

  • Default
    • Windows環境でWindowsLookAndFeelを使用する場合でもJInternalFrameのタイトルバーをマウスの右ボタンでダブルクリックするとそのJInternalFrameが最大化してしまう
  • JPopupMenu
    • ( (BasicInternalFrameUI) f.getUI()).getNorthPane()でタイトルバーを取得し、JComponent#setComponentPopupMenu(popup)JPopupMenuを設定するとマウスの右ボタンクリックでJPopupMenuが開くので右ボタンのダブルクリックによる最大化は実行不可能になる
    • JInternalFrameにJPopupMenuを設定してタイトルを変更する
    • タイトルバーからJPopupMenuを開き、Escキー入力や別コンポーネントをクリックしてポップアップ表示をキャンセルすると再度タイトルバーを左クリックするまでJInternalFrameのリサイズが不可能になるバグ?が存在する
  • WindowsInternalFrameUI
    • WindowsLookAndFeelでのみ動作を変更したい場合はWindowsInternalFrameUI#createBorderListener(...)メソッドをオーバーライドして MouseInputAdapterを継承するBorderListenerがマウスの左ボタンにのみ反応するよう変更することで右ボタンのダブルクリックによる最大化や右ボタンでのJInternalFrameのリサイズを無効にする方法がある
    • 右ボタンでのリサイズ自体が無効なので、上記のJPopupMenuのバグは発生しない
      JInternalFrame f = new JInternalFrame("WindowsInternalFrameUI", true, true, true, true) {
        @Override public void updateUI() {
          super.updateUI();
          setUI(new WindowsInternalFrameUI(this) {
            @Override protected MouseInputAdapter createBorderListener(JInternalFrame w) {
              return new BorderListener() {
                @Override public void mouseClicked(MouseEvent e) {
                  if (SwingUtilities.isLeftMouseButton(e)) {
                    super.mouseClicked(e);
                  }
                }
      
                @Override public void mousePressed(MouseEvent e) {
                  if (SwingUtilities.isLeftMouseButton(e)) {
                    super.mousePressed(e);
                  }
                }
              };
            }
          });
        }
      };
      
  • JLayer
    • JDesktopPaneJLayerを被せてJInternalFrameのタイトルバーがマウスの右ボタンでダブルクリックされた場合のマウスイベントを無視する
    • JInternalFrameのシステムアイコンがダブルクリックされるとJInternalFrameは非表示になるが、このJLayerでは合わせてマウスの右ボタンでダブルクリックを無視するよう設定
    • さらにマウスの右ボタンでのJInternalFrameのリサイズも無効化している
    • JInternalFrame.JDesktopIcon(アイコン化したJInternalFrame)を右ボタンでダブルクリック(復元)した場合も無効化
      • BasicInternalFrameTitlePaneMouseEvent.MOUSE_CLICKEDだが、JInternalFrame.JDesktopIconMouseEvent.MOUSE_CLICKEDイベントでダブルクリックを検出する必要がある(なぜ異なる実装になっているのかの理由は不明)

参考リンク

コメント