GWT - How to retrieve real clicked widget? - gwt

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?

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.

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

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

Related

how to access an widget attached to a treeitem in GWT

I'm using GWT TreeItem Widget in my program. I add the checkboxes in to the treeitems dynamically. The code is given below. Please note these items starting with "ti" are TreeItems which were defined earlier in this code..
private void polulateTree(List<String> single, List<String> multi,
List<String> sub, List<String> local) {
for (String fm:single) {
this.tilftSingleV.addItem(new CheckBox(fm));
}
for (String vm:multi) {
this.tilftMultiV.addItem(new CheckBox(vm));
}
for (String sm:sub) {
this.tilftSubV.addItem(new CheckBox(sm));
}
for (String lr:local) {
this.tilftLocalR.addItem(new CheckBox(lr));
}
}
Now I want to access these checkboxes. I don't find a method within TreeItem widget which returns the Widget attached to a certain index. I'm looking for something like below, which I don't find.
CheckBox chksingle = (CheckBox)tilftSingleV.getWidget(int index)
Any help would be appreciated.
From the gwt documentation:
http://www.gwtproject.org/javadoc/latest/com/google/gwt/user/client/ui/TreeItem.html
getChild(int index): Gets the child at the specified index.
getWidget(): Gets the Widget associated with this tree item.
Widget w = tilftSingleV.getChild(index).getWidget();
if(w instanceof CheckBox)
//Do something with the CheckBox

Disable/mask TabItem's content panel in ExtGwt

I have a TabPanel with two TabItems in ExtGwt. I want to make both the TabItem selectable/clickable but want to disable/read-only the content panel in the TabItem so that user can not perform any action like input text in the textbox or select any field etc. I tried various approaches but it didnot worked for me. I don't want to make the whole tab disable.
This answer may be useful: https://stackoverflow.com/a/2063082/1313968
An alternative approach is to disable all components in the panel, for example just pass your ContentPanel to the following method:
private void containerSetEnabled(final Container container, final boolean enabled) {
for (int widgetIndex = 0; widgetIndex < container.getWidgetCount(); ++widgetIndex) {
final Widget widget = container.getWidget(widgetIndex);
if (widget instanceof Container) {
containerSetEnabled((Container)widget, enabled);
}
else if (widget instanceof Component) {
((Component)widget).setEnabled(false);
}
}
}

take name of tab for TabLayoutPanel

I'm using TabLayoutPanel.
TabLayoutPanel content = new TabLayoutPanel();
FlowPanel fp = new FlowPanel();
content.add(fp,"one");
content.add(fp,"two");
content.add(fp,"tree");
content.addSelectionHandler(new SelectionHandler() {
#Override
public void onSelection(SelectionEvent event) {
//
//How can I take name of selected tab ("one" or "two" ...)
//
}
});
Internally text is converted to either HTML or Label widget when component is added in TabLayoutPanel
Try below code in SelectionHandler
Widget widget=content.getTabWidget(content.getSelectedIndex());
if(widget instanceof Label){
System.out.println(((Label)widget).getText());
}else if(widget instanceof HTML){
System.out.println(((HTML)widget).getHTML());
} else {
System.out.println(widget.getTitle());
}
Note: Always use generic form of SelectionHandler.
You can get a selected widget:
FlowPanel fp = contents.getWidget(contents.getSelectedIndex());
Inside a selection handler you can use:
FlowPanel fp = contents.getWidget(event.getSelectedItem());

GWT SimplePanel can only contain one child widget

Im trying to make a History Handler in my Project so i have a Login "page" and messure "page"
#Override
public void onValueChange(ValueChangeEvent<String> event) {
// TODO Auto-generated method stub
String token = null;
String[] array1 = new String[3];
if (event.getValue()!=null) {
token = event.getValue().trim();
array1=token.split("&",2);
}
if ((token == null) || (token.equals(""))){
clearing();
RootPanel.get("de").add(login, 457, 168);
}
else if (array1[0].equals("messure")){
clearing();
login.init(array1[1].substring(0, 2));
}
else{
clearing();
RootPanel.get("de").add(login, 457, 168);
}
}
and here is the clearing:
private void clearing(){
RootPanel.get("en").clear();
RootPanel.get("de").clear();
}
The Browser refreshbutton works well but when i try to go back and forward i get this:
10:37:56.831 [ERROR] Uncaught exception escaped
com.google.gwt.event.shared.UmbrellaException: Exception caught: SimplePanel can only contain one child widget
its caused by a :
commentBox.add(box);
commentBox is public static...
do i have to change it to a get/set methode to get it work or how?
The exeception is telling you that you are adding more than one element into a SimplePanel
What is your commentBox ? Is it a simple panel ? Are you trying to add element more that once inside ?
You need to create a widget (for example, using a FlowPanel as a container for labels, text boxes, etc.), and then you add this widget to the DialogBox. DialogBox can only accept one widget as its body.

Handling click events from CellTable, how to handle them back to default dispatcher?

I have a CellTable with one custom column where I render it manually and put a FlowPanel with a bunch of HTMLPanel/Anchor/FlowPanel widgets, and among them is DecoratorPanel.
DecoratorPanel renders as a table, of course.
Rendering happens like this:
public class MyExpandableCell extends AbstractCell<String> {
...
#Override
public void render(com.google.gwt.cell.client.Cell.Context context, String value, SafeHtmlBuilder sb) {
if (value != null) {
FlowPanel fp = createDetailsFlowPanel(value);
sb.appendHtmlConstant(fp.getElement().getString());
}
}
Now, I have added a handler for click events to my main CellTable. In my handler I traverse the tree to find a first TR belonging to my CellTable, by checking if it contains "even row" or "odd row" CSS classes.
However, when click happens inside of the DecoratorPanel (which is inside of my cell table's TD), my handler also gets triggered, since the click belongs to the cell table area.
I can detect this my seeing that parent TR does not have CellTable CSS classes.
QUESTION: how can I return processing of such click events to the DecoratorPanel - where it really belongs to? As it is now, my DecoratorPanel does not expand and I think because my click handler intercepts and suppresses all clicks on the CellTable level.
table = setupMyCellTable(PAGE_SIZE, CLIENT_BUNDLE, myCellTableResources);
mydataprovider.addDataDisplay(table);
table.sinkEvents(Event.ONCLICK);
table.addDomHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent e) {
boolean isClick = "click".equals(e.getNativeEvent().getType());
if (isClick) {
Element originalElement = e.getNativeEvent().getEventTarget().cast();
Element element = originalElement;
String ctTrClassEven = CLIENT_BUNDLE.mainCss().cellTableEvenRow();
String ctTrClassEven = CLIENT_BUNDLE.mainCss().cellTableOddRow();
// Looking for closest parent TR which has one
// of the two row class names (for this cellTable):
while (element != null
&& !"tr".equalsIgnoreCase(element.getTagName())
&& !(element.getClassName().contains(ctTrClassEven) ||
element.getClassName().contains(ctTrClassEven))) {
element = element.getParentElement();
}
if (element != null) {
if (element.getClassName().contains(ctTrClassEven)
|| element.getClassName().contains(ctTrClassEven)) {
// Found cell table's TR. Set new TR height.
} else {
// Found TR from DecoratorPanel inside of the celltable's cell.
// Do nothing. But how do I make sure
// that decorator panel processes this click and expands?
return;
// Did not work: NS_ERROR_ILLEGAL_VALUE javascript exception.
// if (originalElement != null) {
// originalElement.dispatchEvent(e.getNativeEvent());
// }
}
} else {
debugStr.setText("(did not find tr)");
}
}
}
}, ClickEvent.getType());
Looks like a bug in GWT, triggered because decorator panel uses table to render itself:
http://code.google.com/p/google-web-toolkit/issues/detail?id=5714
(another example http://code.google.com/p/google-web-toolkit/issues/detail?id=6750)
Fix is expected to be shipped with GWT 2.5.