Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access a GWT menubar popup panel / submenu?

I'm trying to add some mouse listeners to the sub menus/ cascading menus of GWT's MenuBar. Sadly, I cannot seem to access the submenu popuppanel directly - the method to do so (getPopup() ) is private. And you can't access it via reflection due to the way GWT compiles.

Adding a mouse listener to the main menu bar (to detect when the mouse is inside the menu bar boundaries) was nice and simple. But I can't figure out any way to add a mouse listener to tell when the mouse is inside one of the cascading sub menus.

What I am doing is this:

com.google.gwt.user.client.ui.MenuBar myMainBar = new MenuBar();
myMainBar.addDomHandler(menuHoverOutHandler, MouseOutEvent.getType());
myMainBar.addDomHandler(menuHoverOverHandler, MouseOverEvent.getType());

This works great for the actual GWT MenuBar. When I mouse in, the mouseOverEvent triggers. When I mouse out, the MouseOutEvent triggers.

The problem is that if I open a submenu from the main menubar, mousing into that menu will also trigger the MouseOutEvent. I need it not to do that.

When I say submenu I mean something like the ones seen here:

http://www.gwtproject.org/javadoc/latest/com/google/gwt/user/client/ui/MenuBar.html

So as long as I'm in the 'main' bar that lists Style, Fruit, and Term, the mouse events recognize this.

But if I drop down to the sub menu that says Bold, Italicized, More, the mouse events believe I have left the menu bar entirely. I need a way to determine if the mouse is inside one of these submenus. (Or that a submenu of this main menu bar is open somewhere)

You cannot simply do

myMainBar.getPopup()

and add listeners to the resulting PopupPanel as getPopup is private. I'm looking for another way to get to MenuBar.popup

It seems there is no method to tell if one of the sub menus is open, as well, which is a bit perplexing to me. There seems to be a frustrating lack of ability to interact with these submenus, and I am wondering if I am missing something.

like image 420
user2197116 Avatar asked Jun 19 '14 18:06

user2197116


2 Answers

If you add a MouseOverHandler and MouseOutHandler to each of your submenus as opposed to your main menu bar it should do what you want.

For example:

MenuBar subMenu = new MenuBar(true);
subMenu.addItem("Item1", new Command() {
    @Override
    public void execute() {
        Window.alert("Item1 clicked");
    }
});

subMenu.addDomHandler(new MouseOverHandler() {
    @Override
    public void onMouseOver(MouseOverEvent arg0) {
        Window.alert("SubMenu over!");
    }
}, MouseOverEvent.getType());

subMenu.addDomHandler(new MouseOutHandler() {
    @Override
    public void onMouseOut(MouseOutEvent arg0) {
        Window.alert("SubMenu out!");
    }
}, MouseOutEvent.getType());

MenuBar mainMenu = new MenuBar();
mainMenu.addItem("SubMenu", subMenu);

RootPanel.get().add(mainMenu);
like image 163
megadan Avatar answered Sep 21 '22 16:09

megadan


Your problem is related to the logic of events it self: you would like to have a new type of event that triggers only when the mouse moves out of menus and doesn't if it moves between menus.

To do this you could add code that listens to both mouve over and mouse out and compile the available information to understand what is happening.

You can be sure to execute a code after all events passed by using a Scheduler

 Scheduler.get().scheduleDeferred(new Command() {
    public void execute () {
      //check all what happened in a static shared variable, there was a mouse out, was there a mouse over after it? if yes then stay calm; If there wasn't, then trigger a MouseOutOfAllMenus event
    }
  });

this code snippet should be put inside the onMouseOut(), and another code that only updates the state of the static class instance should be put in the onMouseOver(). You can be sure the code in the Scheduler.execute() will execute after the onMouseOver() executed thanks to the Scheduling deferred mechanism. So when you will come to check the state, it will be after the mouse entered to another menu (or didn't); therefore you can know if the user really left the menu items or he entered to a submenu.

Last recommandation: do this code in a separate class so you can have this enrichened menu available as a component for future use. Also keep in mind that by keeping things separate you can test and run automated test scenarios a lot easier.

I hope you understood all I tried to explain, if not, feel free to comment, I'll try my best to answer you

Best Regards,

p.s: when i say a static instance state, it's just for the ease of understanding. It is naturally recommended to avoid the static use to be able to have more than one menu in the same application. By static I mean: an instance that is acessible to all of the components

like image 44
Zied Hamdi Avatar answered Sep 22 '22 16:09

Zied Hamdi