概要

JWindowや装飾なしのJFrameJPopupMenuなどにフォーカス可能なコンポーネントを配置するテストを実行します。

スクリーンショット

Swing/JWindowFocus.png

サンプルコード

JButton button4 = new JButton("JWindow(owner)");
button4.addActionListener(e -> {
  JButton b = (JButton) e.getSource();
  resetEditor(editor, b);
  Point p = b.getLocation();
  p.y += b.getHeight();
  SwingUtilities.convertPointToScreen(p, b.getParent());
  Window window = new JWindow(SwingUtilities.getWindowAncestor(b));
  window.setFocusableWindowState(true);
  window.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
  // window.setAlwaysOnTop(true);
  window.add(editor);
  window.pack();
  window.setLocation(p);
  window.setVisible(true);
  editor.requestFocusInWindow();
});
View in GitHub: Java, Kotlin

解説

  • JPopupMenu
    • JPopupMenu内にフォーカス可能なコンポーネントとしてJTextAreaを配置
    • JFrameのタイトルバーなどをクリックすると自動的にJPopupMenuが非表示になる
    • JPopupMenu内に配置した子コンポーネントのJTextAreaからJPopupMenuが開けない
    • JFrame内にポップアップするLightWeightPopupJPopupMenu#pack()を実行すると子のJTextAreaからフォーカスが移動してしまうのでJTextArea#requestFocusInWindow()で再設定する必要がある
    • JFrame外にポップアップするHeavyWeightPopupJPopupMenu#pack()を実行すると一瞬親JFrameタイトルバーの描画などが乱れる
button1.addActionListener(e -> {
  JButton b = (JButton) e.getSource();
  resetEditor(editor, b);
  JPopupMenu popup = new JPopupMenu();
  popup.setBorder(BorderFactory.createEmptyBorder());
  popup.add(editor);
  popup.pack();
  Point p = b.getLocation();
  p.y += b.getHeight();
  popup.show(this, p.x, p.y);
  editor.requestFocusInWindow();
});
  • JFrame#setUndecorated(true)
    • JFrame#setUndecorated(true)でタイトルバーなどの装飾を非表示にしたJFrameにフォーカス可能なコンポーネントとしてJTextAreaを配置
    • JFrameがアクティブWindowでなくなるためグローバルフォーカスが外れて親JFrameのタイトルバーの描画などが変化する
    • JTextArea外をクリックして編集終了と合わせてJFrameを閉じる場合、親JFrameMouseListenerComponentListenerを追加する必要がある
      • JFrameのタイトルバーをクリックしてもそのイベントを取得する方法がない?ため、その動作でJTextAreaを閉じることができない
JButton button2 = new JButton("JFrame#setUndecorated(true)");
button2.addActionListener(e -> {
  JButton b = (JButton) e.getSource();
  resetEditor(editor, b);
  JFrame window = new JFrame();
  window.setUndecorated(true);
  // window.setAlwaysOnTop(true);
  window.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
  window.add(editor);
  window.pack();
  Point p = b.getLocation();
  p.y += b.getHeight();
  SwingUtilities.convertPointToScreen(p, b.getParent());
  window.setLocation(p);
  window.setVisible(true);
  editor.requestFocusInWindow();
});
  • JWindow()
    • JWindowにフォーカス可能なコンポーネントとしてJTextAreaを配置
    • JFrameを指定していないので非表示のJFrameが親フレームになり、JWindowに配置したコンポーネントがフォーカスを取得できない
    • JWindow#setFocusableWindowState(true)を指定しても効果がない?
    • 非表示のJFrameが別途表示された後(このサンプルではbutton2button4が実行された後)ならマウスでJTextAreaの文字列を選択することなどが可能になる
JButton button3 = new JButton("JWindow()");
button3.addActionListener(e -> {
  JButton b = (JButton) e.getSource();
  resetEditor(editor, b);
  Window window = new JWindow();
  window.setFocusableWindowState(true);
  // window.setAlwaysOnTop(true);
  window.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
  window.add(editor);
  window.pack();
  Point p = b.getLocation();
  p.y += b.getHeight();
  SwingUtilities.convertPointToScreen(p, b.getParent());
  window.setLocation(p);
  window.setVisible(true);
  editor.requestFocusInWindow();
});
  • JWindow(owner)
    • 表示中の親JFrameを所有フレームにしてJWindowを作成し、これにフォーカス可能なコンポーネントとしてJTextAreaを配置
    • JFrameがアクティブWindowのままになるのでそのタイトルバーの描画などは変化しない
    • JTextArea外をクリックして編集終了と合わせてJWindowを閉じる場合、親JFrameMouseListenerComponentListenerを追加する必要がある
      • 装飾なしのJFrameと同様に親JFrameのタイトルバーをクリックしてもそのイベントを取得する方法がない?ため、その動作でJTextAreaを閉じることができない
    • JWindow#setAlwaysOnTop(true)を設定していると別アプリケーションのウィンドウが重なってもその手前にセルエディタが表示されることになるので、代わりにWindow#setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE)を設定して回避

参考リンク

コメント