2009-01-27 43 views
6

Trong quá khứ, khi một người đã JPopupMenu có thể nhìn thấy đó là mục đầu tiên sẽ được chọn theo mặc định: http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.htmlCách chọn mục đầu tiên trong JPopupMenu?

Ngày nay hành vi mặc định là bật lên menu mà không bất kỳ mục đã chọn. Tôi muốn tạo một JPopupMenu với một mục duy nhất sẽ bật lên được chọn và căn giữa dưới con trỏ chuột. Tôi đã quản lý để có được mục để bật lên trung tâm dưới con chuột nhưng tôi JMenuItem từ chối để render như thể nó được chọn. Nếu tôi di chuyển chuột ra khỏi mục và quay lại, chọn đúng cách.

Bất kỳ ý tưởng nào?

Đây là testcase của tôi:

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

Tôi cũng tìm thấy một số hành vi không nhất quán (xem câu trả lời cập nhật của tôi). Bạn có thể xác nhận điều này không? –

+0

Tôi báo cáo đây là lỗi đối với Sun. Tôi sẽ cho bạn biết những gì họ viết lại. – Gili

+0

Đây là báo cáo lỗi liên quan: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6799989 – Gili

Trả lời

0

Ngày nay hành vi mặc định là bật lên menu mà không bất kỳ mục đã chọn.

Thực ra, tôi cho rằng đây là hành vi đúng, ít nhất là trong Windows. Các ứng dụng không phải Java khác cũng làm như vậy. Tôi không nghĩ rằng nó có giá trị phá vỡ quy ước này ngay cả khi chỉ có một mục trong menu. Nếu bạn cảm thấy khác, bạn có thể thiết lập chỉ mục lựa chọn như trong sean.bright's answer.


Vì vậy, cuối cùng tôi đã có cơ hội để thử nó ra trên Java 1.6.0_11, và tìm thấy một số hành vi không phù hợp: Nếu popup menu nhô ra khỏi khung phụ huynh, các mục được chọn tự động; nếu menu bật lên xuất hiện hoàn toàn trong khung chính, thì không có gì được chọn. Âm thanh như một lỗi Swing, mà ít nhất đảm bảo một RFE cho hành vi nhất quán.

+0

+1: Hành vi đúng là bất kỳ nền tảng cụ thể nào cho các chương trình khác (không phải Java). –

+0

Zach, tôi đồng ý với đánh giá chung của bạn nhưng tiếc là điều này không trả lời được câu hỏi của tôi. Tôi muốn * tách ra khỏi hành vi thông thường nhưng tôi thấy không thể làm như vậy. Tôi đang cố gắng để tìm hiểu xem đây là một lỗi Swing hoặc lỗi người dùng. – Gili

+0

Tôi đã gửi báo cáo lỗi với Sun: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6799989 – Gili

0

Điều này thật kỳ lạ.

Tôi đã thử nó với Windows, và với Java 1.5.0_08 và thậm chí 1.6.0_07 Element đầu tiên được chọn tự động, như bạn mong đợi nó được.

Vì vậy, tôi đã thử nó với 1.6.0_11 và không hoạt động nữa, yếu tố đầu tiên không được chọn ban đầu. Chọn phần tử trong vùng chọnModel dường như không giúp ích gì.

Một cách giải quyết khác (mà tôi hoàn toàn không tự hào) là di chuyển chuột tự động sau khi hiển thị menu bật lên, sử dụng tọa độ của MouseEvent. Có lẽ ai đó có một ý tưởng tốt hơn?

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

Bí mật hóa ra là 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() thực sự là một giải pháp tốt, nhưng nó sẽ không hoạt động khi bạn sẽ cố gắng trước khi chọn menu phụ của JPopupMenu của bạn (nó sẽ ẩn menu cha). Ngoài ra, nó làm rối loạn các hành vi điều hướng bàn phím khác (bạn không thể nhấn trái để ẩn menu phụ, v.v.)

Unfortunatelly, không có giải pháp tốt cho câu hỏi này trong Swing ... Giải pháp của tôi là xấu xí, nhưng thật đáng buồn hiện công việc hoàn hảo:

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')); 
     } 
    }}); 
} 

Như bạn thấy, tôi về cơ bản mô phỏng 'Down' Keyboard Key-ép trên popupmenu ...

Một giải pháp tốt hơn có thể không phải để Hardcodedly mô phỏng VK_DOWN, nhưng để đọc bản đồ đầu vào của Popup và xác định KeyCode có nghĩa là "chọn mục trình đơn tiếp theo" - nhưng tôi nghĩ rằng hầu hết chúng ta sẽ nhận được cùng với hack này ...

Bạn cũng có thể muốn để xem xét phương pháp này, chọn mục của trình đơn khi nó được chọn Nó sử dụng metho trước đó 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) { 
     } 
    }); 
} 
+0

er, PopupUtils là gì? Dường như không phải là một phần của JDK của tôi. –

+0

ngoài việc đó, giải pháp mô phỏng phím mũi tên xuống không hoạt động. –

Các vấn đề liên quan