- PR -

JMenuBarの動作

1
投稿者投稿内容
bonbon
会議室デビュー日: 2003/05/30
投稿数: 8
投稿日時: 2004-02-13 10:25
 SwingのJMenuBarを使ってナビゲーションバーを作成しています。
 JMenuBarのデフォルトの動きは
1)JMenuBarのJMenuをクリックするとJPopupMenuが表示される。
2)異なるJMenuにマウスが入るとJPopupMenuが表示される。
3)3)のJMenuをクリックするとJPopupMenuが閉じる。
となっています。
 この動きを
4)JMenuにマウスが入るとJPopupMenuが表示される。
5)JMenuからマウスが出るとJPopupMenuが閉じる。
という動きに変えたいと思っています。
 MouseAdapter、addMouseListener、mouseEntered又はmouseExitを
使えば、できそうなのですがaddMouseListenerを行う対象オブジェクトを
はじめ、具体策がわかりません。
 お手数ですがご教示よろしくお願いします。
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2004-02-13 13:26
こんにちは、Wataです。
なぜこのような挙動が必要なのかわかりませんが、
引用:

bonbonさんの書き込み (2004-02-13 10:25) より:
4)JMenuにマウスが入るとJPopupMenuが表示される。


はJMenuにMouseListenerを追加して、mouseEnteredイベントを拾って、
JMenu#processMenuDragMouseEvent()をコールすることによってできましたよ。
# MenuDragMouseEventは自作します。

5)の消すほうはあまり上手い方法は思いつきませんが、
多分、JMenu#getPopupMenu()で取得したポップアップメニューに
リスナーを追加することになると思います。
bonbon
会議室デビュー日: 2003/05/30
投稿数: 8
投稿日時: 2004-02-13 18:13
 ご回答ありがとうございます。
 早速、作成してみます。

 このような挙動にしたいのはJMenuにマウスを入れるとJPopupMenuが表示され、
JMenuからマウスを入れるとJPopupMenuが閉じるという挙動の方がユーザーは分
かり易いと思うからです。
 そもそもナビゲーションバーを作るなら、Javaではなく、JavaScriptで十分
かもしれませんが。
 現在、誰でもPARAMの中を変更するだけでナビゲーションメニューを変更できないか
ということにトライ中です。
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2004-02-13 18:18
こんにちは、さくらばです。

引用:

bonbonさんの書き込み (2004-02-13 10:25) より:
4)JMenuにマウスが入るとJPopupMenuが表示される。
5)JMenuからマウスが出るとJPopupMenuが閉じる。
という動きに変えたいと思っています。
 MouseAdapter、addMouseListener、mouseEntered又はmouseExitを
使えば、できそうなのですがaddMouseListenerを行う対象オブジェクトを
はじめ、具体策がわかりません。



単に JMenu に MouseListener をつけるだけではだめです。表示される
ポップアップメニューも MouseListener を add するようにします。

ただ、面倒なのがメニューからポップアップメニューにマウスカーソルを
動かすときに、メニューにもポップアップメニューにも含まれない場所が
あるということです。ここを通る間にイベント処理をさせないように工夫
が必要でした。

というわけで、こんなサンプルを作ってみました。Win XP で J2SE 1.4.2_03
と J2SE 1.5 beta で動作チェックしています。

ちょっと長いのですが、ご容赦を。

コード:
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;

public class MenuSample {
    public MenuSample() {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(100, 100, 200, 100);
        
        JMenuBar bar = new JMenuBar();

        MenuCreator creator = new MenuCreator("File");
        JMenu menu = creator.getMenu();
        menu.add(new JMenuItem("Open"));
        menu.add(new JMenuItem("Save"));
        menu.add(new JMenuItem("Exit"));
        bar.add(menu);

        creator = new MenuCreator("Edit");
        menu = creator.getMenu();
        menu.add(new JMenuItem("Copy"));
        menu.add(new JMenuItem("Cut"));
        menu.add(new JMenuItem("Paste"));
        bar.add(menu);

        frame.setJMenuBar(bar);
        
        frame.setVisible(true);        
    }
    
    class MenuCreator {
        private MenuSelectionManager mng;
        private JMenu menu;
        private boolean flag;

        public MenuCreator(String title) {
	    mng = MenuSelectionManager.defaultManager();
	    
            menu = new JMenu(title);
            menu.addMouseListener(new MouseAdapter() {
                public void mouseEntered(MouseEvent event) {
		    // メニューにマウスが入ったらポップアップメニューを表示
		    // MenuSelectionManager を使用したのはクリックされた時の
                    // 処理と同じにするため
                    MenuElement[] me = new MenuElement[3];
                    me[0] = (MenuElement)menu.getParent();
                    me[1] = menu;
                    me[2] = menu.getPopupMenu();
                    mng.setSelectedPath(me);
                }

                public void mouseExited(MouseEvent event) {
		    // メニューからポップアップメニューや他のメニューに遷移した時の
		    // ことを考えて invokeLater を使用
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
			    // 他のメニューが選択状態だったらそのまま
			    JMenuBar parent = (JMenuBar)menu.getParent();
			    int count = parent.getMenuCount();
			    for (int i = 0; i < count; i++) {
				JMenu mm = parent.getMenu(i);
				if (mm.isSelected() && mm != menu) {
				    return;
				}
			    }

			    // ポップアップメニューが表示されていたら
			    // ポップアップメニューを閉じて、
			    // 選択状態を非選択状態にする
                            if (!flag) {
                                MenuElement[] me = new MenuElement[2];
                                me[0] = (MenuElement)menu.getParent();
                                mng.setSelectedPath(me);
                            }
                        }
                    });
                }
            });        

            JPopupMenu popup = menu.getPopupMenu();
            popup.addMouseListener(new MouseAdapter() {
                public void mouseEntered(MouseEvent event) {
                    flag = true;
                }
                
                public void mouseExited(MouseEvent event) {
		    // ポップアップメニューからマウスが出たら
		    // ポップアップメニューを閉じて、
		    // メニューを選択状態から非選択状態にする
                    JPopupMenu popup = (JPopupMenu)event.getSource();
                    Point point = event.getPoint();
                    if (!popup.contains(point.x, point.y)) {
                        MenuElement[] me = new MenuElement[1];
                        me[0] = (MenuElement)menu.getParent();
                        mng.setSelectedPath(me);

                        flag = false;
                    }
                }
            });        
        }
        
        public JMenu getMenu() {
            return menu;
        }
    }

    public static void main(String[] args) {
        new MenuSample();
    }
}

Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2004-02-13 19:18
引用:

さくらばさんの書き込み (2004-02-13 18:18) より:
こんにちは、さくらばです。

単に JMenu に MouseListener をつけるだけではだめです。表示される
ポップアップメニューも MouseListener を add するようにします。

ただ、面倒なのがメニューからポップアップメニューにマウスカーソルを
動かすときに、メニューにもポップアップメニューにも含まれない場所が
あるということです。ここを通る間にイベント処理をさせないように工夫
が必要でした。

(後略)


うーむ。勉強になります。
ところで、JMenuを入れ子にする場合はもう少し改造が要りそうですね。
bonbon
会議室デビュー日: 2003/05/30
投稿数: 8
投稿日時: 2004-02-14 19:54
 さくらばさん。
 貴重なプログラムのご教示ありがとうございます。
 参考にさせていただきます。

 しかし、JMenuBarのデフォルトの動きを変更するだけでも結構、
複雑なのですね。
 JAVAの勉強として、JMenuBarのデフォルトでもつアクションを調べて
みたい気もします。それにはソースを見るしかないのでしょうか?
1

スキルアップ/キャリアアップ(JOB@IT)