GWT - How to retrieve real clicked widget?

2019-09-05 11:45发布

问题:

I have onClick event on somePanel. And I click on it and it works. But.. How to retrieve real click target? When I click on panel which is inside od somePanel it show me that I click on somePanel..

I know we have this:

Element e = Element.as( event.getNativeEvent().getEventTarget());

But i returns element - I want widget..

How to do this?

回答1:

I would use the feature in gwtquery to get the widget associated with a given element: https://code.google.com/p/gwtquery/wiki/GettingStarted#Manipulating_your_widgets

Widget = $(e).widget();

The problem is that the element clicked couldn't be the element associated with the widget but a child. In this case you could use gquery selectors to traverse the dom until you get its parent widget based on some css property.

// Most gwt widgets contains a class .gwt- but this could fail
// so use a more accurate selector than the one in this example
Widget = $(e).closest("[class*='.gwt-']")

If you wanted to do it by yourself, taking a look to the method getAssociatedWidget in GQuery gives you the solution:

  EventListener listener = DOM.getEventListener(e);
  // No listener attached to the element, so no widget exist for this element
  if (listener == null) {
    return null;
  }
  if (listener instanceof Widget) {
    // GWT uses the widget as event listener
    return (Widget) listener;
  }

EDITED: here you have a working example:

import static com.google.gwt.query.client.GQuery.*;

  // A panel with some widgets
  Panel panel = new VerticalPanel();
  final HTML widget1 = new HTML("<span>Foo</span> <span>Bar</span");
  final HTML widget2 = new HTML("<span>Foo</span> <span>Bar</span");
  final HTML widget3 = new HTML("<span>Foo</span> <span>Bar</span");
  panel.add(widget1);
  panel.add(widget2);
  panel.add(widget3);

  // we need to wrap our panel with a widget supporting click events
  FocusPanel wrapper = new FocusPanel();
  wrapper.add(panel);
  RootPanel.get().add(wrapper);

  wrapper.addClickHandler(new ClickHandler() {
    public void onClick(ClickEvent event) {
      // The element is not the HTML widget clicked but the span element
      Element e = event.getNativeEvent().getEventTarget().cast();

      // Using gquery to get the closest widget to the clicked element
      // We take advanrage of HTML widgets having gwt-HTML class
      Widget w = $(e).closest(".gwt-HTML").widget();

      if (w == widget1) {
        Window.alert("Clicked on widget 1");
      } else if (w == widget2) {
        Window.alert("Clicked on widget 2");
      } else if (w == widget3) {
        Window.alert("Clicked on widget 3");
      } else {
        Window.alert("Clicked on a non GWT HTML widget");
      }
    }
  });


回答2:

This is an old question, but both answers are wrong. If you are using a GWT EventListener and want the widget that is the source of the event, then you simply use the event.getSource() method of the event and cast it to the original object type.

Unless there is something that I am missing in the question here.



回答3:

An alternative approach, if you already know all of the widgets that you want to check against, would be to use the DOM.isOrHasChild(Element) or Element.isOrHasChild(Node).

For example:

public void onClick(ClickEvent event) {

    Element targetElem = Element.as(event.getNativeEvent().getEventTarget());

    Widget targetWidget = null;

    if (widgetA.getElement().isOrHasChild(targetElem) {
        targetWidget = widgetA;
    }
    else if (widgetB.getElement().isOrHasChild(targetElem) {
        targetWidget = widgetA;
    }
    .....

    if (targetWidget != null) {
        // You found you widget - Yay!
    }
    else {
        // No widget found - Bummer!
    }

}

This approach only works if you know the widgets you are testing against up front. The benefit is that you now have an particular widget reference rather then a generic reference to 'some' widget that you might have to do additional checks against.

For example, you could have done the following if widgetA was a subclass of TextBox called MySpecialTextBox:

MySpecialTextBox widgetA;

if (widgetA.getElement().isOrHasChild(targetElem) {
    widgetA.someSpecialMethod();
}