WisdomSoft - for your serial experiences.

10.3 ポップアップ

画面上の任意の場所にメニュー項目を表示するにはポップアップメニューを使います。

10.3.1 メニューコマンドの表示

ポップアップコンポーネントを用いれば、メニューバー以外の自由な位置にメニュー項目を表示させることができます。ポップアップメニューを表示するには javax.swing.JPopupMenu クラスを使います。

javax.swing.JPopupMenu クラス
java.lang.Object
  |
  +--java.awt.Component
        |
        +--java.awt.Container
              |
              +--javax.swing.JComponent
                    |
                    +--javax.swing.JPopupMenu
public class JPopupMenu extends JComponent implements Accessible, MenuElement

JPopupMenu クラスは、メニュー項目を管理する部分で JMenu クラスと良く似ていますが、show() メソッドを使って何らかのコンポーネント上の任意の位置に表示することができる点で異なります。

表1 JPopupMenu クラスのコンストラクタとメソッド(抜粋)
コンストラクタ 解説
public JPopupMenu() デフォルトの JPopupMenu を構築する。
public JPopupMenu(String label) 指定されたタイトルの PopupMenu を構築する。
メソッド
public JMenuItem add(Action a)

指定された Action オブジェクトからメニュー項目を追加します。

public JMenuItem add(String s) 指定されたテキストを持つ新しいメニュー項目を追加する。
public JMenuItem add(JMenuItem menuItem) 指定されたメニュー項目をメニューの末尾に追加する。
public void addSeparator() 末尾に新しいセパレータを追加する。
public void insert(Component component, int index) 指定されたコンポーネントを、メニューの指定された位置に挿入する。
public void insert(Action a, int index) 指定された Action オブジェクトを、メニュー項目として指定の位置に挿入する。
public void remove(int pos) 指定されたインデックスにあるコンポーネントを削除する。
public void setLabel(String label) ポップアップメニューのラベルを設定する。
public String getLabel() ポップアップメニューのラベルを返す。
public void show(Component invoker, int x, int y) コンポーネント内の指定座標に、ポップアップメニューを表示する。

JPopupMenu もメニュー項目として JMenu を追加できるため、メニュー項目を階層化することができます。マウスのボタンがクリックされるタイミングで show() メソッドを呼び出し、コンポーネントに関連するポップアップメニューを表示すると良いでしょう。そうすれば、ユーザーは素早く目的の機能にアクセスすることができるようになります。

通常、ポップアップメニューは軽量コンポーネントとして描画されますが、ポップアップメニューを描画する矩形がアプリケーションウィンドウの外にはみ出してしまう場合、システムに依存する重量ウィンドウを新しく作成し、このウィンドウにメニュー項目が描画されます。軽量コンポーネントの方が効率的ですが、Swing は必要に応じてポップアップメニューを重量ウィンドウに表示するのです。

コード1
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Test extends JFrame implements ActionListener {
	public static void main(String args[]) {
		JFrame win = new Test();
		win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.show();
	}

	private JPopupMenu popup = new JPopupMenu();
	public Test() {
		JMenu menu = new JMenu("JMenu");
		menu.add("JMenu-MenuString 1").addActionListener(this);
		menu.add("JMenu-MenuString 2").addActionListener(this);

		popup.add("Menu String 1").addActionListener(this);
		popup.add("Menu String 2").addActionListener(this);
		popup.add(menu);

		addMouseListener(new MouseAdapter() {
			public void mouseReleased(MouseEvent e) {
				Point pt = e.getPoint();
				popup.show(e.getComponent() , pt.x , pt.y);
			}
		});
	}

	public void actionPerformed(ActionEvent e) {
		AbstractButton item = (AbstractButton)e.getSource();
		JOptionPane.showMessageDialog(this, item.getText());
	}
}
実行結果
コード1 実行結果

コード1は、ウィンドウのクライアント領域をクリックすると、マウスリスナとして登録した mouseReleased() メソッドが呼び出されます。このタイミングで show() メソッドを使ってポップアップメニューを表示しています。表示されるポップアップメニューは、ウィンドウを親とし、マウスがクリックされた座標にひょうじされるでしょう。

ただし、ポップアプメニューを実装する場合は、特定のプラットフォームに依存しないように注意する必要があります。特に Macintosh 環境のマウスには右クリックが存在しないことを意識する必要があります。

10.3.2 ポップアップイベント

ポップアップメニューが表示されたり、表示されているポップアップメニューが非表示になるタイミングで、ポップアップメニューリスナが呼び出されます。ポップアップメニューの項目などが何らかの値を参照している場合、ポップアップが表示されるタイミングで同期を取るなどの処理を実現するには、このリスナを利用すると便利でしょう。

ポップアップメニューリスナは javax.swing.event.PopupMenuListener インタフェースを実装しなければなりません。このインタフェースには、ポップアップが表示される直前に呼び出される popupMenuWillBecomeVisible() メソッド、非表示になる直前に呼び出される popupMenuWillBecomeInvisible() メソッド、そして取り消されたときに呼び出される popupMenuCanceled() メソッドが宣言されています。

PopupMenuListener インタフェース popupMenuWillBecomeVisible() メソッド
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
PopupMenuListener インタフェース popupMenuWillBecomeInvisible() メソッド
public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
PopupMenuListener インタフェース popupMenuCanceled() メソッド
public void popupMenuCanceled(PopupMenuEvent e)

これらのメソッドに渡されるイベントオブジェクトは javax.swing.event.PopupMenuEvent クラスです。 このクラスは EventObject を継承し、イベントを発生させた源泉オブジェクトを提供するだけで、新しいメソッドは公開されていません。

javax.swing.event.PopupMenuEvent クラス
java.lang.Object
  |
  +--java.util.EventObject
        |
        +--javax.swing.event.PopupMenuEvent
public class PopupMenuEvent extends EventObject

ポップアップメニューリスナをポップアップメニューに追加するには JPopupMenu クラスの addPopupMenuListener() メソッドを使います。リスナへの通知が不要になれば removePopupMenuListener() メソッドからリスナを解除することができます。現在登録されているリスナの配列は getPopupMenuListeners() メソッドから得ることができます。

PopupMenuEvent クラス addPopupMenuListener() メソッド
public void addPopupMenuListener(PopupMenuListener l)
PopupMenuEvent クラス removePopupMenuListener() メソッド
public void removePopupMenuListener(PopupMenuListener l)
PopupMenuEvent クラス getPopupMenuListeners() メソッド
public PopupMenuListener[] getPopupMenuListeners()

JPopupMenu オブジェクトが show() メソッドで呼び出されたり、ユーザーの入力などで表示されているポップアップメニューが非表示になる瞬間を捕捉する必要がある場合に使います。

コード2
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

public class Test extends JFrame implements PopupMenuListener {
	public static void main(String args[]) {
		JFrame win = new Test();
		win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		win.setBounds(10 , 10 , 400 , 300);
		win.show();
	}

	private JPopupMenu popup = new JPopupMenu();
	private JCheckBoxMenuItem menuItem1 =
		new JCheckBoxMenuItem("CheckMenu 1");
	private JCheckBoxMenuItem menuItem2 =
		new JCheckBoxMenuItem("CheckMenu 2");
	private JCheckBox button1 = new JCheckBox("CheckBox 1");
	private JCheckBox button2 = new JCheckBox("CheckBox 2");
	public Test() {
		getContentPane().setLayout(new FlowLayout());
		getContentPane().add(button1);
		getContentPane().add(button2);

		popup.add(menuItem1);
		popup.add(menuItem2);
		popup.addPopupMenuListener(this);

		addMouseListener(new MouseAdapter() {
			public void mouseReleased(MouseEvent e) {
				Point pt = e.getPoint();
				popup.show(e.getComponent() , pt.x , pt.y);
			}
		});
	}

	public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
		menuItem1.setSelected(button1.isSelected());
		menuItem2.setSelected(button2.isSelected());
		System.out.println("popupMenuWillBecomeVisible");
	}
	public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
		System.out.println("popupMenuWillBecomeInvisible");
	}
	public void popupMenuCanceled(PopupMenuEvent e) {
		System.out.println("popupMenuCanceled");
	}
}
実行結果
コード2 実行結果

コード2は、ウィンドウに 2 つのチェックボックスを表示し、ポップアップメニューのチェックメニュー項目がチェックボックスと同期するというプログラムです。ウィンドウのクライアント領域上でマウスをクリックするとポップアップメニューが表示されますが、この直前にポップアップメニューリスナが呼び出されています。リスナが呼び出されると標準出力に文字列を出力するので、発生したタイミングを確認できると思います。