Store IsWidget instances in Panel instead of Widget?

58 views
Skip to first unread message

Ed

unread,
Feb 26, 2011, 7:07:15 AM2/26/11
to Google Web Toolkit Contributors
Why not store the IsWidget instances as children in the Panel, instead
of the contained Widget?

At this moment Panels contain a WidgetCollection instance that
contains Widget instances. Why not use store the IsWidget instances.
I don't think this breaks anything as Widget implements IsWidget.
I think this improves the lazy behavior of Widgets.

I love the IsWidget interface as it improves the lazy creation of
widgets, testing, and result in the creation of widget interfaces.
However, at the moment that you want to store it in a panel, you have
to store the contained widget, which leads to nasty situations.

Example:
I have a widget that I add to some Panel:
class TitleWidget implements IsWidget, HasText {}

and the implementation (uses the UiBinder):
class TitleWidgetUi implements LineTitle {

...
...
public Widget asWidget() {
return getEnsureUiWidget();
}

private Widget getEnsureUiWidget() {
if (this.uiWidget == null) { // lazy creation
this.uiWidget = GWT.<TitleWidgetUiBinder>
create(TitleWidgetUiBinder.class).createAndBindUi(this);
}
return this.uiWidget;
}
}

Usage:
Panel panel = new FlowPanel();
panel.add(new TitleWidget(createTitleText()); // panel will store
the contained widget and not the TitleWidget instance

private String createTitleText() {
return "Logged in member: " + getMemberName());
}

As you can see, the title widget contains some member name.
If his member name changes, I iterate through the widgets contained in
Panel and in case it implements HasText, I update the title text.
Code:
for (Widget widget: panel.iterator()) {
if (widget instanceof HasText) {
( (HasText) widget).setText(createTitleText());
}
}

However, this will never work as you would expect as the panel will
contain the Widget contained in the created TitleWidget instance and
not the TitleWidget instance itself. And the contained widget isn't
implementing HasText.

The above situation is common I think as the member name is contained
in a global data model and I don't allow listeners to subscribe them
self because of possible memory leaks. Memory leaks can easily occur
when widget are added and removed and don't remove their listener.
This was what happened in the past, so I changed this (we don't have
weak listeners in gwt/javascript like in swt). So a changed member
name is pushed on the event bus, controllers will receive it and
further distribute it to the potential interested widgets.
I might react: Stupid that a widget doesn't remove his listener when
removed. Of course, this would be the perfect case, but in complex
situations it's easily forgotten and almost unavailable (my
experience)

Work around: let LineTitleUi extend Composite, such that Panel will
store it directly and not the contained widget. but that then you will
loze the lazy behavior and you can't test it anymore outside of GWT.
Especially this latter one is important and important result of the
IsWidget interface.. In this case the IsWidget loses his value and
could also be removed..

What do you think ?

Stephen Haberman

unread,
Feb 27, 2011, 10:22:42 PM2/27/11
to google-web-tool...@googlegroups.com, Ed

> public Widget asWidget() {
> return getEnsureUiWidget();
> }

You shouldn't be doing this. asWidget wasn't added to allow lazy
initialization of widgets.

It was added so that dummy widgets can pretend to be widgets--but
only in tests. When not testing, the assertion:

assert widget.asWidget() == widget

Should always pass.

In other words, the only implementations of asWidget should ever be:

A) In a real widget:

public Widget asWidget() {
return this;
}

B) In a stub/mock/fake widget:

public Widget asWidget() {
throw new RuntimeException("no, i'm not a real widget!");
}

While your use of asWidget is creative, it's not at all the intent, and
so it's not surprising you're seeing odd results.

- Stephen

Ed

unread,
Feb 28, 2011, 4:46:45 AM2/28/11
to Google Web Toolkit Contributors
Thanks, for the clear explanation. I wasn't aware of this.
If that's how it was designed, I understand it, but I don't think this
is well explained in the documentation and I hope most GWT developers
know this.
And why not extend this functionality to the way I use it so it might
become more useful?

- Ed
Reply all
Reply to author
Forward
0 new messages