org.eclipse.swt.widgets.Control.requestLayout()
public void requestLayout () {
getShell ().layout (new Control[] {this}, SWT.DEFER);
}
org.eclipse.swt.widgets.Composite.layout(Control[], int) 代码
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);
}
}
在第①行中,该控件及其所有祖先都立即布局,为什么
Control.requestLayout()
的文档这么说
控件不会同步重新定位
另外,每次调用这个方法时,这个控件和它的所有祖先都会被布局,为什么文档这么说
此方法运行速度快,仅标记对未来参与延迟布局的控制。
在布局发生之前多次调用此方法是一种廉价的无操作。
是的,确实是异步完成的。
SWT.DEFER
标志导致layout
代码执行:
setLayoutDeferred (true);
display.addLayoutDeferred (this);
在致电
update
之前。
setLayoutDeferred(true)
调用会增加 Composite 中 layoutCount
字段的值。 display.addLayoutDeferred
将 Composite 添加到延迟布局列表中。
在
updateLayout
方法中,代码的第一部分是
void updateLayout (boolean all) {
Composite parent = findDeferredControl ();
if (parent != null) {
parent.state |= LAYOUT_CHILD;
return;
}
...
findDeferredControl
方法测试之前在 Composite 或其任何父级中设置的 layoutCount
值:
Composite findDeferredControl () {
return layoutCount > 0 ? this : parent.findDeferredControl ();
}
所以布局在调用过程中并没有更新。相反,更新是在 Display 处理其延迟布局列表时完成的。这将在下次执行
readAndDispatch
方法时完成。