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.
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);
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With