Go to Contents Go to Java Page
J2SE 1.5 虎の穴
 
 

どこでもとびだすポップアップメニュー JPopupMenu

 
 
Tiger ポップアップはできるものの
 
 

ポップアップメニューは使いにくいと思っていませんか。私は思っていました。

なぜかというと、ポップアップをとびださせるためには、自分でイベント処理をおこなってポップアップメニューを表示させなければいけなかったからです。

以前の方法で書いてみましょう。

サンプルのソース OldPopupMenuSample.java

ポップアップをさせたいコンポーネントに対してリスナ登録して、イベントが発生したらそれがポップアップさせる条件下を調べて、表示という流れです。

        menu = new JPopupMenu();
        menu.add(new JMenuItem("item 1"));
        menu.add(new JMenuItem("item 2"));
        menu.add(new JMenuItem("item 3"));
 
        JTextArea area = new JTextArea(20, 20);
        area.addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent event) {
                    popupMenu(event);
                }
 
                public void mouseReleased(MouseEvent event) {
                    popupMenu(event);
                }
            });

ここでは JTextArea コンポーネントに対してポップアップメニューを出そうとしています。そのために area に対して addMouseListener メソッドをコールしています。ポップアップさせるかどうかは次のように判定します。

    private void popupMenu(MouseEvent event) {
        if (event.isPopupTrigger()) {
            menu.show(event.getComponent(), event.getX(), event.getY());
        }
    }

MouseEvent クラスにはポップアップさせるかどうかを調べるためのメソッド isPopupTrigger が定義されているので、これを使用します。Windows の場合は右クリックで isPopuTrigger メソッドの戻り値が true になります。

そうしたら、JPopupMenu オブジェクトを表示します。表示させる位置はマウスポインタがある位置にしたほうがいいので、イベントから取得したマウスポインタの位置を使用しています。

たかがポップアップメニューにこれだけのことをしなくてはならないのです。

うーん、面倒くさい。

 

 
 
Tiger Tiger ではどうよ?
 
 

さて、Tiger です。

Tiger では JComponent クラスに setComponentPopupMenu メソッドが新たに定義されました。

これを使えばリスナ登録やイベント処理などなしに簡単にポップアップメニューをつけることができます。

先ほどのサンプルを Tiger の方法で書き直してみましょう。

サンプルのソース PopupMenuSample1.java

同じように JTextArea にポップアップをさせます。

        menu = new JPopupMenu();
        menu.add(new JMenuItem("item 1"));
        menu.add(new JMenuItem("item 2"));
        menu.add(new JMenuItem("item 3"));
 
        JTextArea area = new JTextArea(20, 20);
        area.setComponentPopupMenu(menu);

えっ、これだけ、と思いませんか。今までの苦労はなんだったんだろう。

 

 
 
Tiger どのコンポーネントでも使えるか?
 
 

簡単になったのはいいのですが、どうもすべての Swing のコンポーネントがポップアップメニューを出せるわけではないようです。

それを確かめるためにこんなサンプルを作ってみました。

サンプルのソース PopupMenuSample2.java

主要なコンポーネントに対して setComponentPopupMenu メソッドをコールしています。たとえば JButton に対しては次のようになっています。

        JButton button = new JButton("Button");
        button.setComponentPopupMenu(popupMenu);
        button.setBorder(new TitledBorder("JButton"));
        frame.getContentPane().add(button);

これを実行すると次のようになります。

PopupMenuSample2

このサンプルで 1 つ 1 つポップアップメニューが表示されるか調べてみました。その結果が次の表です。

コンポーネント 結果
JButton
JCheckBox
JComboBox
JLabel ×
JList
JMenuBar ×
JPanel ×
JRadioButton
コンポーネント 結果
JSlider
JTabbedPane
JTable
JTextArea
JTextField
JToggleButton
JToolBar
JTree

JLabel クラスが使えないのは意外でしたが、そんなもんなのでしょうか。JMenuBar クラスで使えないのは逆に当然ですね。

 

 
 
Tiger ポップアップメニューを継承する
 
 

ポップアップメニューを継承するといっても、JPopupMenu クラスを派生させるわけではありません。

GUI ではコンテナとコンポーネントは親子関係にありますが、親が使っているポップアップメニューを子供も使いたいということです。

サンプルのソース PopupMenuSample3.java

ポップアップメニューを継承するには JComponent#setInheritsPopupMenu メソッドを使用します。このメソッドは引数が boolean で、true の時に親のポップアップメニューをそのまま使えるようになります。

        JButton button = new JButton("Button");
        button.setBorder(new TitledBorder("JButton"));
        panel2.add(button);
 
        button.setInheritsPopupMenu(true);

PopupMenuSample3 クラスの中ではフレームのコンテントペインにポップアップメニューを設定しています。

コンテントペインには JPanel オブジェクトをはり、その中にもう 1 つ JPanel オブジェクトをはり、その中に JButton オブジェクトをはっています。

ポップアップメニューの継承

ところが、上述したように JPanel クラスはポップアップメニューを表示させることができません。

さて、このサンプルでは JButton オブジェクトにポップアップメニューが表示させることはできるのでしょうか。やってみましょう。

ポップアップメニューの継承

なんとできました。でも、JPanel のところではやっぱりポップアップメニューは表示されません。なんか不思議な感じです。

 

 
 
Tiger おわりに
 
 

今までポップアップメニューを使うにはイベント処理をしなくてはいけなかったので面倒だったのが、Tiger ではずいぶんすっきりしてしまいました。

このような改善は大歓迎。今まで面倒だからといって使っていなかった人も、どんどん使ってみましょう。

 

今回使用したサンプルはここからダウンロードできます。

 

(Oct. 2004)

 
 
Go to Contents Go to Java Page