21

時々、正しくレイアウトすることを完全に拒否する SWT コンポジットに遭遇することがあります。コンポジットで dispose を呼び出し、それを別のものに置き換えたときに、これに遭遇することがよくあります。ただし、この場合に厳密に限定されるわけではないようです。

この問題が発生した場合、約 50% の確率で、問題のあるコンポジットに対して and を呼び出すことができpack()layout()すべてがうまくいきます。ただし、約 50% の場合、これを行う必要があります。

Point p = c.getSize();
c.setSize(p.x+1, p.y+1);
c.setSize(p);

これは、レイアウト マネージャーなどのほぼすべての組み合わせで発生しました。

シンプルで再現性のある素敵なケースがあればいいのにと思いますが、そうではありません。誰かがこの問題を認識して、「まあ、xyz がありません....」と言ってくれることを願っています。

4

4 に答える 4

31

レイアウトのキャッシュが古く、更新する必要があるように見えます。

SWT のレイアウトはキャッシュをサポートし、通常はコントロールの優先サイズ、またはキャッシュしたいものをキャッシュします。

public abstract class Layout {
    protected abstract Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache);
    protected boolean flushCache (Control control) {...}
    protected abstract void layout (Composite composite, boolean flushCache);
}

私は SWT プログラミング (元 Swing プログラマー) には比較的慣れていませんが、レイアウトが適切に更新されないという同様の状況に遭遇しました。私は通常、レイアウトがキャッシュをフラッシュする他のレイアウト方法を使用してそれらを解決することができました。

layout(boolean changed)

layout(boolean changed, boolean allChildren)
于 2009-02-25T15:48:27.973 に答える
21

その間に、実行時にコントロール階層の一部を変更またはサイズ変更するときの SWT の欠点についてもう少し学びました。が最小または優先コンテンツ サイズを調整する必要がある場合は、ScrolledCompositeおよびも明示的に更新する必要があります。ExpandBar

変更されたコントロールのコントロール階層のレイアウトを再検証する小さなヘルパー メソッドを作成しました。

public static void revalidateLayout (Control control) {

    Control c = control;
    do {
        if (c instanceof ExpandBar) {
            ExpandBar expandBar = (ExpandBar) c;
            for (ExpandItem expandItem : expandBar.getItems()) {
                expandItem
                    .setHeight(expandItem.getControl().computeSize(expandBar.getSize().x, SWT.DEFAULT, true).y);
            }
        }
        c = c.getParent();

    } while (c != null && c.getParent() != null && !(c instanceof ScrolledComposite));

    if (c instanceof ScrolledComposite) {
        ScrolledComposite scrolledComposite = (ScrolledComposite) c;
        if (scrolledComposite.getExpandHorizontal() || scrolledComposite.getExpandVertical()) {
            scrolledComposite
                .setMinSize(scrolledComposite.getContent().computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
        } else {
            scrolledComposite.getContent().pack(true);
        }
    }
    if (c instanceof Composite) {
        Composite composite = (Composite) c;
        composite.layout(true, true);
    }
}
于 2009-03-26T16:45:34.740 に答える
4

Composite.changed(Control[] children) に気付きました。私が数年前に読んだ広範な記事があります:

http://www.eclipse.org/articles/article.php?file=Article-Understanding-Layouts/index.html

この記事では、Composite.layout(boolean changed, boolean all) を呼び出してレイアウトを更新することについても言及しています。 ." それはすべて正しいことであり、それ以来私がやってきたことです。しかし、1 つまたはいくつかのコントロールの要件が変更されたためにレイアウトを更新したい場合、レイアウト キャッシュの利点が基本的に無効になるため、これは望ましいことではありません。

GridLayout に多数の StyledText ウィジェットがあり、そのうちの 1 つのサイズを変更する必要があるとします。StyledText で computeSize() を呼び出すと、非常にコストがかかります。これの代わりに:

違う:

parent.layout(true);

...要件が変更されていなくても、すべての子で computeSize() を呼び出します。これを行う必要があります:

右:

parent.changed(new Control[] { theChangedChild });

その後、どちらか

rootComposite.layout(false, true);

また

parent.layout(false);

あまり直感的ではありません。layout() へのパラメーターの名前が悪いだけです。「変更済み」と呼ぶ代わりに、「ignoreCache」などと呼ぶべきでした。直観的なことは、何かが変化したときに「true」を渡すことです。代わりに「false」を渡す必要がありますが、その前に changed() で変更されたコントロールだけのキャッシュを無効にします...

changed() を呼び出すと、その親の親 Control だけのキャッシュも再帰的に無効になることに注意してください。これは完全に理にかなっています。そのため、layout() を呼び出すときは、変更されたコントロールの親のサイズが応答して変更されるか変更されないことがわかっている場合を除き、all=true を指定してルート コンポジット (ほとんどの場合シェル) で呼び出す必要があります。

于 2015-10-12T09:31:26.323 に答える