org.eclipse.swt.widgets.Control.requestLayout()
public void requestLayout () {
getShell ().layout (new Control[] {this}, SWT.DEFER);
}
org.eclipse.swt.widgets.Composite.layout(Control[], int) code
public void layout (Control [] changed, int flags) {
checkWidget ();
if (changed != null) {
for (Control control : changed) {
if (control == null) error (SWT.ERROR_INVALID_ARGUMENT);
if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT);
boolean ancestor = false;
Composite composite = control.parent;
while (composite != null) {
ancestor = composite == this;
if (ancestor) break;
composite = composite.parent;
}
if (!ancestor) error (SWT.ERROR_INVALID_PARENT);
}
int updateCount = 0;
Composite [] update = new Composite [16];
for (Control element : changed) {
Control child = element;
Composite composite = child.parent;
// Update layout when the list of children has changed.
// See bug 497812.
child.markLayout(false, false);
while (child != this) {
if (composite.layout != null) {
composite.state |= LAYOUT_NEEDED;
if (!composite.layout.flushCache (child)) {
composite.state |= LAYOUT_CHANGED;
}
}
if (updateCount == update.length) {
Composite [] newUpdate = new Composite [update.length + 16];
System.arraycopy (update, 0, newUpdate, 0, update.length);
update = newUpdate;
}
child = update [updateCount++] = composite;
composite = child.parent;
}
}
if (!display.externalEventLoop && (flags & SWT.DEFER) != 0) {
setLayoutDeferred (true);
display.addLayoutDeferred (this);
}
// ① here! here! here!
for (int i=updateCount-1; i>=0; i--) {
update [i].updateLayout (false);
}
} else {
if (layout == null && (flags & SWT.ALL) == 0) return;
markLayout ((flags & SWT.CHANGED) != 0, (flags & SWT.ALL) != 0);
if (!display.externalEventLoop && (flags & SWT.DEFER) != 0) {
setLayoutDeferred (true);
display.addLayoutDeferred (this);
}
updateLayout ((flags & SWT.ALL) != 0);
}
}
In line ① , this control and all of its ancestors are laid out immediately , why does the documentation for Control.requestLayout()
say that
The control will not be repositioned synchronously
Additionally, each time this method is called, this control and all of its ancestors are laid out, why does the documentation say that
This method is fast-running and only marks the control for future participation in a deferred layout.
Invoking this method multiple times before the layout occurs is aninexpensive no-op.
Yes, it is really done asynchronously.
The SWT.DEFER
flag causes the layout
code to execute:
setLayoutDeferred (true);
display.addLayoutDeferred (this);
before the calls to update
.
The setLayoutDeferred(true)
call increments the value of the layoutCount
field in the Composite. display.addLayoutDeferred
adds the Composite to the list of deferred layouts.
In the updateLayout
method the first part of the code is
void updateLayout (boolean all) {
Composite parent = findDeferredControl ();
if (parent != null) {
parent.state |= LAYOUT_CHILD;
return;
}
...
The findDeferredControl
method tests the layoutCount
value set earlier in the Composite or any of its parents:
Composite findDeferredControl () {
return layoutCount > 0 ? this : parent.findDeferredControl ();
}
So the layout is not updated during the call. Instead the update is done when Display processed its list of deferred layouts. This is done the next time the readAndDispatch
method is executed.