Absolute positioning relative to other widgets

53 views
Skip to first unread message

Stephen Cagle

unread,
May 1, 2009, 7:12:03 PM5/1/09
to Google Web Toolkit
I have a Composite widget within which I have overridden the onResize
() method. Some of the element widgets of this widget position
themselves relative to other widgets. That is to say, I sometimes
position widget X using .getAbsoluteTop() and .getOffsetHeight().
Unfortunately, sometimes .getAbsoluteTop sometimes returns a pretty
random value. I think this is because I am re-populating/creating a
lot of the widgets upon resize. So maybe I am getting the size of the
widget "as it is being built". What should I do to deal with this. I
need to position things absolutely relative to other widgets, but
within the onResize() method, I am getting (occasionally) odd results?

Adam T

unread,
May 2, 2009, 12:14:12 AM5/2/09
to Google Web Toolkit
sometimes it's worth wrapping any repositioning up in a
DeferredCommand to give the browser a chance, i.e. take you code that
does something like this:

int x = X.getAbsoluteTop;
int h = X.getOffsetHeight();
W.setWidgetPostition(x,y);
W.setWidth(h/2+"px");

and make it

DeferredCommand.addCommand(new Command(){
public void execute(){
int x = X.getAbsoluteTop;
int h = X.getOffsetHeight();
W.setWidgetPostition(x,y);
W.setWidth(h/2+"px");
}
});

now the positioning code will execute a little later giving the
browser chance to have redrawn everything and you should get more
consistent answers.

//Adam

Stephen Cagle

unread,
May 2, 2009, 8:00:49 PM5/2/09
to Google Web Toolkit
First of all, Thank You Adam. This is one of those things that I spent
like 4 hours on and finally just asked about.

I put my absolute positioning code inside a DefferedCommand. Have not
seen it fail yet. So thank you, it seems to work.


Still, I do wonder. What is the deterministically appropriate way to
deal with this? For all I know the DefferedCommand may be the
appropriate way to deal with this, as it may truly guarantee that code
is not run till after all other events are run. Assuming that
"repositioning stuff as things are added to the DOM" is just another
event, then as long as DefferedCommand always guarantees that it will
add to the end, then it is probably correct.

However, is there some more direct way to do this. Like, could I wrap
a widget in something (or override some handler) such that I can
guarantee execution of code only after the widget has been fully
positioned and their currently exist not other DOM modifying events in
the queue?

Also, in closing, is there more information somewhere on exactly how
widgets are added, positioned, and rendered. I would also be
interested in any callbacks (or equivalent) that I can override at any
point in said process. Thanks all.

Adam T

unread,
May 3, 2009, 2:00:53 AM5/3/09
to Google Web Toolkit
Hi Stephen, I feel this is just one of those challenging areas in
GWT. There's no "event" in GWT that tells you DOM has finished layout
activities, but there is a point where you expect this to be the case
in the normal lifecycle of a widget.

In the Widget lifecycle there are four key points you can override
that in a way act as "events":

* onAttach() - called when a widget is attached to the browser's
document.
* onLoad() - called immediately after a widget becomes attached to
the browser's document.
* onUnload() - called immediately before a widget will be detached
from the browser's document.
* onDetach() - called when a widget is detached from the browser's
document

The one of interest here is onLoad(), where it's fairly safe to assume
that everything DOM attribute wise is sorted out by then. I've still
found it wise to give the browser some time by wrapping any dimension
stuff in a DeferredCommand within the onLoad() method; I'm not 100%
convinced it is necessary, but I like to live on the safe side in an
effect library I'm building (http://code.google.com/p/gwt-fx/).

I have to admit, I'm not aware of a onResize() method to override in
Widget or Composite class, so can't really comment on how that would
work (out of interest, where is it in standard GWT?).

DeferredCommand itself is a little bit of a trick, although it says
"allows you to execute code after all currently pending event handlers
have completed" it's really based on timers rather than hooking into
the browser event queue and checking all is done before firing your
command - that said, it works.

Hope that gives you a bit more info.

//Adam

Vitrums

unread,
Dec 7, 2012, 5:27:22 PM12/7/12
to google-we...@googlegroups.com, Google Web Toolkit
I'm not exactly aware of the reason why do I repeatedly return to this topic. But it seem like there have been existing an issue of what is described here all the time for me. And I've already encountered it countless times on my way with implementing tooltips, popups, sliding menus, suggest boxes and so on.  Perhaps, it's all about the sense, that there must exist some sort of solution for all this stuff, that would be both pretty, and effective. As an example of such magic, I can give you the Element#scrollIntoView() method, which can scroll the area right to the specified element, and do whatever it's possible to ensure that the latter will become visible to user. If browser can do that, why wouldn't it help us to adjust the positioning of our absolutely positioned widgets?

So there's only one suitable solution, that I could come up with:
- supply your absolutely positioned widgets with some sort of recalculator instead of statically allocating it upon the construction. This recalculator would have methods like:

public double getLeft(); // returns absolute left, that is relative to some widget
public double getTop();
...etc.

Once an event, that might somehow break your layout occurred (say, window got resized, or the whole layout switched in some sort of sliding animation), make sure the objects, which were responsible for creation of those absolutely positioned widgets, or the widgets themselves, are listeners of such sort of events, and that they call recalculator's methods to handle the event properly. The best way not to make it too ugly is to have an access to one global EventBus and fire/catch those events in means of the latter.

Ugly? Well, in absence of other solution it's worth to try. At least this one works for me.
Reply all
Reply to author
Forward
0 new messages