2009-09-23 2 views
3

최근 우리는 메뉴 용도로 GWT MenuBar를 응용 프로그램의 일부에 첨부했습니다.GWT MenuBar 하위 메뉴는 어떻게 자동 숨 깁니 까?

은 기본적으로 당신이 할 수있을만큼 쉽게 최상위 메뉴, 마우스 오버시 하위 메뉴가 열려 :

menubar.setAutoOpen(true); 

나는 또한 자동으로 하위 메뉴를 숨기고 싶을 때 사용자의 마우스 하위 메뉴를 종료합니다. 이상하게도 너무 갑자기 사라지는 것을 막기위한 지연과 함께하지만, 나는 숨어있는 것만으로 해결할 것입니다.

이것은 내장되어 있지 않은 것으로 보이며 GWT의 MenuItem 객체는 UIObject를 직접 서브 클래스로 지정합니다. 즉, 비교적 사소한 onBrowserEvent()가 없거나 마우스 리스너를 첨부 할 수있는 곳을 의미합니다. 아마도 MenuItem과 sinking/unsinking 이벤트를 확장하면이 동작을 추가 할 수 있지만 이것이 최선의 방법인지 확신 할 수 없습니다.

그래서 GWT 하위 메뉴를 자동 숨김하는 가장 좋은 방법은 무엇입니까?

감사합니다.

답변

2

유사한 무언가를 달성하기 위해 무서운 해킹을 시도한 후에 우리는 GWT Portlets framework의 일부로 우리 자신의 cascading menu을 작성했습니다. 다음과 같은 HTML 템플릿의 메뉴 항목과 하위 메뉴를 표시합니다.

<a href="#home">Home</a> 
<a href="#submenu1()">Sub Menu 1</a> 
<a href="#away">Away</a> 

<div id="submenu1"> 
    <a href="#hello_world">Hello World</a> 
    <a href="#free_memory">Free Memory</a> 
    <a href="#submenu2()">Sub Menu 2</a> 
</div> 

<div id="submenu2"> 
    <a href="#command_demo">Command Demo</a> 
    <a href="#command1()">Command1</a> 
    <a href="#command2(arg1,arg2)">Command2</a> 
</div> 

메서드 호출처럼 보이는 URL은 CommandEvent를 브로드 캐스팅합니다. 다른 것들은 평소처럼 역사 토큰 변경을 유발합니다. 작동중인 메뉴를 보려면 online demo을보십시오.

+0

아아는 끔찍한 해킹은 우리가해야했을 것입니다. 데모를 좋아하지만 프로젝트에 다른 프레임 워크를 추가하는 것은이 시점에서 일어나지 않을 것입니다. 제안을 주셔서 감사합니다. – bikesandcode

2

여기 완벽하지 상당히 완벽한 솔루션,이다, 코드 뒤에 설명 :

public class MyMenuBar extends Composite { 

    private class OpenTab implements ScheduledCommand { 
     private String wid; 

     public OpenTab(String windowId) { 
      wid = windowId; 
     } 

     @Override 
     public void execute() { 
      WinUtl.newAppTab(wid); 
     } 
    } 

    interface MyMenuBarUiBinder extends UiBinder<Widget, MyMenuBar> {} 

    private static MyMenuBarUiBinder uiBinder = 
           GWT.create(MyMenuBarUiBinder.class); 

    @UiField MenuBar mainMenu; 

    @UiField MenuBar subsMenu; 
    @UiField MenuItem subsChoice1; 
    @UiField MenuItem subsChoice2; 
    @UiField MenuItem subsChoice3; 

    @UiField MenuBar svcPrvdrMenu; 
    @UiField MenuItem svcPrvdrChoice1; 
    @UiField MenuItem svcPrvdrChoice2; 

    @UiField MenuBar netMgtMenu; 
    @UiField MenuItem netMgtChoice1; 

    @UiField MenuBar reportsMenu; 
    @UiField MenuItem reportsChoice1; 

    @UiField MenuBar auditsMenu; 
    @UiField MenuItem auditsChoice1; 

    @UiField MenuBar securityMenu; 
    @UiField MenuItem securityChoice1; 

    @UiField MenuBar helpMenu; 
    @UiField MenuItem helpChoice1; 

    private boolean subMenuPopped = false; 
    private boolean subMenuEntered = false; 

    private static Type<MouseOverHandler> OVR_EVT = MouseOverEvent.getType(); 
    private static Type<MouseOutHandler> OUT_EVT = MouseOutEvent.getType(); 

    private MouseOverHandler mainOverHandler = new MouseOverHandler() { 
     @Override 
     public void onMouseOver(MouseOverEvent event) { 
      subMenuPopped = true; 
     } 
    }; 

    private MouseOutHandler mainOutHandler = new MouseOutHandler() { 
     @Override 
     public void onMouseOut(MouseOutEvent event) { 
      Element e = event.getRelativeElement() 
      boolean movedUp = (event.getRelativeY(e) < 0); 
      if ((movedUp && subMenuPopped) || subMenuEntered) { 
       subMenuPopped = false; 
       subMenuEntered = false; 
       mainMenu.closeAllChildren(true); 
      } 
     } 
    }; 

    private MouseOverHandler subOverHandler = new MouseOverHandler() { 
     @Override 
     public void onMouseOver(MouseOverEvent event) { 
      subMenuEntered = true; 
     } 
    }; 

    private MouseOutHandler subOutHandler = new MouseOutHandler() { 
     @Override 
     public void onMouseOut(MouseOutEvent event) { 
      subMenuPopped = false; 
      subMenuEntered = false; 
      mainMenu.closeAllChildren(true); 
     } 
    }; 

    public MyMenuBar() { 
     initWidget(uiBinder.createAndBindUi(this)); 

     mainMenu.addStyleName("npac-MenuBar"); 
     mainMenu.setAutoOpen(true); 
     mainMenu.setAnimationEnabled(true); 
     mainMenu.setFocusOnHoverEnabled(true); 

     subsChoice1.setScheduledCommand(new OpenTab(Names.Wid.NPA)); 

     mainMenu.addDomHandler(mainOverHandler, OVR_EVT); 
     mainMenu.addDomHandler(mainOutHandler, OUT_EVT); 

     addHandlers(subsMenu); 
     addHandlers(svcPrvdrMenu); 
     addHandlers(netMgtMenu); 
     addHandlers(reportsMenu); 
     addHandlers(auditsMenu); 
     addHandlers(securityMenu); 
     addHandlers(helpMenu); 
    } 

    private void addHandlers(MenuBar m) { 
     m.addDomHandler(subOverHandler, OVR_EVT); 
     m.addDomHandler(subOutHandler, OUT_EVT); 
    } 
} 

이는 사용자가 다음에는 mainMenu (하위 메뉴 종료) 떨어져 UP 마이스 mouseOver로 하위 메뉴를 엽니 사건을 처리합니다. SubMenu (서브 메뉴는 열린 채로)의 어느 한면을 지나서 대각선으로 움직이는 마우스를 처리하지 않습니다. 확실히 향상시킬 수 있지만 작동하도록하고 싶습니다 .--)

+0

이 답변으로 저를 도왔습니다. 매우 비슷한 것을 만들기 위해 제공된 아이디어와 코드를 사용했습니다. 그럼에도 불구하고 내 메뉴에는 하위 메뉴 (MenuBar의 MenuBar)가 중첩되어 있으므로 코드는 고려하지 않고 여전히 다루고 있습니다. 다시 한 번 감사드립니다. – Diego

0

끔찍한 해킹이 필요 없습니다. Java 내의 CSS를 사용하여 하위 메뉴가있는 MenuBar 자동 숨기기를 구현할 수 있습니다. Parent + Children 드롭 다운 메뉴에서 mouseover opening과 mouseOut 클로저를 사용하여 다른 사람들이 사용할 수 있도록 각 부분에 대한 설명과 함께 완전히 작동하는 예제를 만들었습니다.

사람들이 목격 한 일반적인 문제는 ((JMenu) e.getSource())를 실행하는 것입니다. doClick(); mouseEntered는 JMenu 부모 중 하나에 대한 클릭을 시뮬레이트하지만 MouseExited 메서드에 단순히 추가 할 수는 없습니다. MouseListener는 자식 MenuItems 및 JMenu 부모에 연결되어야하기 때문에. (MenuBar에 대한 일반적인 할당에서는 수행하지 않습니다 - 부모 JMenu 객체에만 붙임).

또한 마우스가 전체 메뉴 구조 (예 : 하위 메뉴 드롭 다운)를 떠난 경우에만 MouseExit 수신기에서 "닫기"메서드를 실행하려고하면 문제가 발생합니다.다음은

가 완벽하게 작동 대답은 내 실제 응용 프로그램에서 가져온 것입니다 :

내가 마우스 아웃에 가까운 메뉴를 해결하는 방법은 추적 할 생성자의 상단에 부울 변수 "isMouseOut"를 실행하는 것이 었습니다 , 그리고 사용자가 메뉴와 상호 작용할 때 여러 개의 MouseIn-MouseOut 이벤트를 추적하기 위해 좀 더 OO 친숙한 방식으로 MouseListener를 할당하십시오. boolean "isMouseOut"상태에 따라 동작하는 별도의 menuClear 메서드를 호출합니다. 이 클래스는 MouseListener를 구현합니다. 이것이 그 방법입니다.

먼저이 배열에 모든 메뉴 항목을 추가하는 ArrayList를 만듭니다. 그래서 같이 : MenuBar을위한

for (Component c : aMenuItms) { 
     if (c instanceof JMenuItem) { 
      c.addMouseListener(ml); 
     } 
    } 

이제 설정 JMenu를 부모 :

// Now set JMenu parents on MenuBar 
    final JMenu mnFile = new JMenu("File"); 
    menuBar.add(mnFile).setFont(menuFont); 
    final JMenu mnView = new JMenu("View"); 
    menuBar.add(mnView).setFont(menuFont); 
    final JMenu mnHelp = new JMenu("Help"); 
    menuBar.add(mnHelp).setFont(menuFont); 

Font menuFont = new Font("Arial", Font.PLAIN, 12); 
    JMenuBar menuBar = new JMenuBar(); 
    getContentPane().add(menuBar, BorderLayout.NORTH); 

// Array of MenuItems 
    ArrayList<JMenuItem> aMenuItms = new ArrayList<JMenuItem>(); 
    JMenuItem mntmRefresh = new JMenuItem("Refresh"); 
    JMenuItem mntmNew = new JMenuItem("New"); 
    JMenuItem mntmNormal = new JMenuItem("Normal"); 
    JMenuItem mntmMax = new JMenuItem("Max"); 
    JMenuItem mntmStatus = new JMenuItem("Status"); 
    JMenuItem mntmFeedback = new JMenuItem("Send Feedback"); 
    JMenuItem mntmEtsyTWebsite = new JMenuItem("EtsyT website"); 
    JMenuItem mntmAbout = new JMenuItem("About"); 

    aMenuItms.add(mntmRefresh); 
    aMenuItms.add(mntmNew); 
    aMenuItms.add(mntmNormal); 
    aMenuItms.add(mntmMax); 
    aMenuItms.add(mntmStatus); 
    aMenuItms.add(mntmFeedback); 
    aMenuItms.add(mntmEtsyTWebsite); 
    aMenuItms.add(mntmAbout); 

다음에() 루프를 사용하여 모든 MouseListener를 추가하는이 단계에서 ArrayList를 반복 그런 다음 JMenu 부모에게 드롭 다운 메뉴 항목 어린이를 추가하십시오.

// Now set menuItems as children of JMenu parents 
    mnFile.add(mntmRefresh).setFont(menuFont); 
    mnFile.add(mntmNew).setFont(menuFont); 
    mnView.add(mntmNormal).setFont(menuFont); 
    mnView.add(mntmMax).setFont(menuFont); 
    mnHelp.add(mntmStatus).setFont(menuFont); 
    mnHelp.add(mntmFeedback).setFont(menuFont); 
    mnHelp.add(mntmEtsyTWebsite).setFont(menuFont); 
    mnHelp.add(mntmAbout).setFont(menuFont); 
,

은 별도의 단계로는 JMenu 부모에있는 MouseListener를 추가

이제 아이는 menuItem 요소 모두가 부모 JMenu를 요소와의 MenuBar 자체에 분리되어 자신의 청취자를 가지고
for (Component c : menuBar.getComponents()) { 
     if (c instanceof JMenu) { 
      c.addMouseListener(ml); 
     } 
    } 

- 파악하는 것이 중요하다 MouseOver (이 예제에서는 3x JMenu 부모)에서 메뉴를 자동으로 열 수 있도록 MouseListener() 인스턴스화 내의 객체 유형 또한 자식 예외 오류를 피하고 메뉴 구조의 mouseOUT을 명확하게 식별 할 수 있습니다. 마우스 위치는. 다음과 같이의 MouseListener은 다음과 같습니다

MouseListener ml = new MouseListener() { 
     public void mouseClicked(MouseEvent e) { 
     } 

     public void mousePressed(MouseEvent e) { 
     } 

     public void mouseReleased(MouseEvent e) { 
     } 

     public void mouseExited(MouseEvent e) { 
      isMouseOut = true; 
      timerMenuClear(); 
     } 

     public void mouseEntered(MouseEvent e) { 
      isMouseOut = false; 
      Object eSource = e.getSource(); 
      if(eSource == mnHelp || eSource == mnView || eSource == mnFile){ 
       ((JMenu) eSource).doClick(); 
      } 
     } 
    }; 

위는 그들 만이 하위 메뉴 드롭 다운에 대한 트리거과 마찬가지로 마우스가 (이 예에서는 3 배)이 JMenu를 '부모'로 클릭 시뮬레이션합니다. timerMenuClear() 메소드는 어떤 selectedpath 포인트는 실제로 마우스의 시점에서 방송했습니다 비워 MenuSelectionManager에 다음과 같이 요청합니다

public void timerMenuClear(){ 
    ActionListener task = new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      if(isMouseOut == true){ 
       System.out.println("Timer"); 
      MenuSelectionManager.defaultManager().clearSelectedPath(); 
      } 
     } 
    };   
    //Delay timer half a second to ensure real mouseOUT 
    Timer timer = new Timer(1000, task); 
    timer.setInitialDelay(500);   
    timer.setRepeats(false); 
    timer.start(); 
} 

그것은 내가 개발하는 동안 JVM 내에서 액세스 할 수있는 가치를 어떻게 모니터링, 나에게 약간의 테스트를했다 - 그러나 그것은 치료를한다! 심지어 중첩 된 메뉴와 함께 :) 많은 사람들이이 예제를 매우 유용하게 사용하기를 바랍니다.

0

사용이 코드 :

public class MenuBarExt extends MenuBar { 

public MenuBarExt() 
{ 
    super(); 
} 

@Override 
public void onBrowserEvent(Event event) 
{ 
    switch (DOM.eventGetType(event)) 
    { 
     case Event.ONMOUSEOUT: 
      closeAllChildren(false); 
      break; 
     default: 
      super.onBrowserEvent(event); 
      break; 

    } 
    super.onBrowserEvent(event); 
} 

} 
관련 문제