7

以前は、JPopupMenu可視化すると最初の項目がデフォルトで選択されていました: http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.html

現在、デフォルトの動作は、アイテムを選択せず​​にメニューをポップアップすることです。JPopupMenuマウス ポインターの下で選択されて中央にポップアップ表示される単一のアイテムを作成したいと思います。アイテムをマウスの下の中央にポップアップさせることはできましたが、JMenuItem選択されているかのようにレンダリングすることを拒否しています。マウスをアイテムの外に移動して戻すと、適切に選択されます。

何か案は?

ここに私のテストケースがあります:

import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

public class Test extends JFrame
{
    public static void main(String[] args)
    {
        JFrame frame = new JFrame();
        frame.setSize(800, 600);
        frame.getContentPane().addMouseListener(new MouseAdapter()
        {
            @Override
            public void mousePressed(MouseEvent e)
            {
                if (e.isPopupTrigger())
                    popupTriggered(e);
            }

            @Override
            public void mouseReleased(MouseEvent e)
            {
                if (e.isPopupTrigger())
                    popupTriggered(e);
            }

            private void popupTriggered(MouseEvent e)
            {
                JPopupMenu menu = new JPopupMenu();
                final JMenuItem item = new JMenuItem("This is a JMenuItem");
                menu.add(item);
                Point point = e.getPoint();
                int x = point.x - (item.getPreferredSize().width / 2);
                int y = point.y - (item.getPreferredSize().height / 2);
                menu.show((Component) e.getSource(), x, y);
            }
        });
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setVisible(true);
    }
}
4

4 に答える 4

8

秘密が判明MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, ...});

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;

/**
 * Demonstrates programmatic {@link JMenuItem} selection;
 * specifically how to make the first item selected by default
 */
public class TestPopup extends JFrame {
  public static void main(String[] args) {
    final JFrame frame = new JFrame("TestPopup");
    frame.setSize(640, 480);
    frame.getContentPane().addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent e) {
        if (e.isPopupTrigger()) {
          popupTriggered(e);
        }
      }
      private void popupTriggered(MouseEvent e) {
        final JPopupMenu menu = new JPopupMenu();
        final JMenuItem item0 = new JMenuItem("JMenuItem 0");
        final JMenuItem item1 = new JMenuItem("JMenuItem 1");
        menu.add(item0);
        menu.add(item1);
        menu.pack();
        // use invokeLater or just do this after the menu has been shown
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, item0});
          }
        });
        int x = (int) ((int) (frame.getSize().width - (menu.getPreferredSize().width / 2.)) / 2.);
        int y = (int) ((int) (frame.getSize().height - (menu.getPreferredSize().height / 2.)) / 2.);
        menu.show(frame, x, y);
        // doesn't work:
        //item0.setSelected(true);
        // doesn't work:
        //menu.getSelectionModel().setSelectedIndex(0);
        // bingo; see also MenuKeyListener / MenuKeyEvent
//        MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, item0});
      }
    });
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}
于 2009-11-27T23:30:51.863 に答える
1

MenuSelectionManager.defaultManager()は確かに優れたソリューションですが、JPopupMenuのサブメニューを事前に選択しようとすると機能しません(親メニューが非表示になります)。また、他のキーボードナビゲーション動作を台無しにします(左を押してサブメニューを非表示にすることはできませんなど)。

残念ながら、Swingにはこの質問に対する良い解決策はありません...私の解決策は醜いですが、悲しいことに仕事は完璧です:

public static void setMenuSelectedIndex(final JPopupMenu popupMenu, final int index) {
    SwingUtilities.invokeLater(new Runnable(){public void run()
    {
        for (int i=0; i < index+1; i++) {
            popupMenu.dispatchEvent(new KeyEvent(popupMenu, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_DOWN, '\0'));
        }
    }});
}

ご覧のとおり、私は基本的に「下」のキーボードキーをシミュレートしています-ポップアップメニューで押す...

より良い解決策は、VK_DOWNをハードコードでシミュレートするのではなく、ポップアップの入力マップを読んで、どのKeyCodeが「次のメニュー項目を選択」を意味するかを判断することです。

メニューの項目が選択されると選択するこの方法もご覧ください。以前の方法を利用しています。

public static void setSelectedIndexWhenVisible(final JMenu menu, final int index) {
    menu.getPopupMenu().addPopupMenuListener(new PopupMenuListener() {
        @Override
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            PopupUtils.setMenuSelectedIndex(menu.getPopupMenu(), index);
            menu.getPopupMenu().removePopupMenuListener(this);
        }

        @Override
        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
        }

        @Override
        public void popupMenuCanceled(PopupMenuEvent e) {
        }
    });
}
于 2011-10-13T13:03:34.090 に答える
1

現在、デフォルトの動作は、アイテムを選択せず​​にメニューをポップアップすることです。

実際、少なくとも Windows では、これが正しい動作であると私は主張します。他の非 Java アプリケーションもこれを行います。メニューに項目が 1 つしかない場合でも、この規則を破る価値はないと思います。そうでない場合は、sean.bright's answer のように選択インデックスを設定できます。


そこで、ようやく Java で試してみた1.6.0_11ところ、一貫性のない動作がいくつか見つかりました。ポップアップ メニューが親フレームからはみ出している場合、項目は自動的に選択されます。ポップアップ メニューが完全に親フレーム内に表示される場合、何も選択されていません。Swing のバグのように聞こえますが、これは少なくとも一貫した動作のために RFE を保証します。

于 2009-01-27T01:40:25.940 に答える
0

これは奇妙です。

Windows で試してみたところ、Java 1.5.0_081.6.0_07でさえ、最初の要素が自動的に選択されました。

だから私は1.6.0_11で試してみましたが、もう機能しません。最初の要素は最初は選択されていません。selectionModel で要素を選択しても役に立たないようです。

1 つの回避策 (私はまったく誇りに思っているわけではありません) は、ポップアップ メニューを表示した後に、MouseEventの座標を使用してマウスを自動的に移動することです。多分誰かがより良いアイデアを持っていますか?

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

public class SelectedPopupMenu extends JFrame {

    public SelectedPopupMenu() {
        addMouseListener(new MouseAdapter() {
            public void mouseClicked(final MouseEvent e) {
                JPopupMenu popupMenu = new JPopupMenu();
                popupMenu.add(new JMenuItem("Test-Item"));
                popupMenu.add(new JMenuItem("Test-Item-2"));
                // do not care to really hit the center of the popup
                popupMenu.show(SelectedPopupMenu.this, e.getX() - 30, e.getY() - 10);
                try {
                    // shake mouse, so that first element is selected even in Java 1.6.0_11
                    Robot robot = new Robot();
                    robot.mouseMove(e.getX() + 1, e.getY());
                    robot.mouseMove(e.getX(), e.getY());
                } catch (AWTException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public static void main(String[] args) {
        JFrame frame = new SelectedPopupMenu();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }
}
于 2009-01-28T19:10:37.037 に答える