Control.requestLayout()真的是异步完成的吗?

问题描述 投票:0回答:1

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()
的文档这么说

控件不会同步重新定位

另外,每次调用这个方法时,这个控件和它的所有祖先都会被布局,为什么文档这么说

此方法运行速度快,仅标记对未来参与延迟布局的控制。

在布局发生之前多次调用此方法是一种廉价的无操作。

eclipse swt
1个回答
0
投票

是的,确实是异步完成的。

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
方法时完成。

© www.soinside.com 2019 - 2024. All rights reserved.