2009-01-27 59 views
6

在過去,當一個人做了一個JPopupMenu可見它的第一個項目將在默認情況下都被選擇:http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.html如何選擇JPopupMenu中的第一項?

如今的默認行爲是彈出菜單中選擇沒有任何項目。我想創建一個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); 
    } 
} 
+0

我也發現了一些不一致的行爲(請參閱我的更新回答)。你能證實這一點嗎? – 2009-01-30 03:20:37

+0

我向Sun報告這是一個錯誤。我會讓你知道他們回信。 – Gili 2009-01-30 19:48:18

+0

以下是相關的錯誤報告:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6799989 – Gili 2009-02-28 17:37:35

回答

0

如今的默認行爲是彈出菜單中選擇沒有任何項目。

其實,我認爲這是正確的行爲,至少在Windows中。其他非Java應用程序也這樣做。即使菜單中只有一個項目,我認爲不值得打破這個慣例。如果您覺得不適合,可以按照sean.bright's answer中的設置選擇索引。


所以,我終於嘗試一下Java的1.6.0_11的機會,發現了一些不一致的行爲:如果在彈出菜單中伸出父框架,該項目會自動選擇;如果彈出式菜單完全出現在父框架內,則不會選擇任何內容。聽起來像一個Swing bug,它至少保證RFE的一致行爲。

0

這很奇怪。

我與Windows試了一下,用的Java 1.5.0_08甚至1.6.0_07第一要素是自動選擇,因爲你希望它是。

所以,我想它1.6.0_11,它不工作了,第一個元素是不是最初選擇。 在selectionModel中選擇元素似乎沒有幫助。

一種解決方法(我並不爲此感到驕傲)是在顯示彈出式菜單後,使用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); 
    } 
} 
6

祕密原來是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); 
    } 
} 
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')); 
     } 
    }}); 
} 

正如你可以看到的彈出菜單,我基本上模擬「向下」鍵盤按鍵事件...

更好的解決方案可能不是Hardcodedly模擬VK_DOWN,而是讀取Popup的輸入地圖,並確定哪個KeyCode的意思是「選擇下一個菜單項」 - 但我認爲我們大多數人會與這種黑客相處...

您可能還想要看看這種方法,一旦它被選中,它就選擇一個菜單的項目 它利用了以前的方法d

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) { 
     } 
    }); 
} 
相關問題