2009-02-25 51 views
18

有時我們會遇到一個完全拒絕正確放置的SWT組合。我們經常遇到這種情況,因爲我們在一個複合體上調用了處置,然後用另一個替換了它;雖然它似乎並不嚴格限於這種情況。爲什麼SWT Composite有時需要調用resize()才能正確佈局?

當我們遇到這個問題時,大約有50%的時間,我們可以撥打pack()layout()在違規組合上,一切都會好的。大約50%的時間,但是,我們不得不這樣做:

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

我們過這種情況與幾乎所有的佈局管理器和這樣的組合。

我希望我有一個很好,簡單,可重複的情況,但我不知道。我希望有人會認識到這個問題,並說:「呃,你錯過了xyz ....」

回答

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編程(原擺動程序員),但遇到佈局未正確更新的類似情況。我通常能夠使用其他佈局方法,也將導致佈局刷新其高速緩存來解決這些問題:

layout(boolean changed) 

layout(boolean changed, boolean allChildren) 

希望幫助...

+1

+1並接受。希望我能+10這一個:P – Jared 2009-02-25 16:27:49

+0

我有問題的作者同樣的問題。佈局(真實,真實)幫助了我。 – ka3ak 2012-04-19 12:38:37

+0

很好的回答! +1 – 2012-04-26 11:41:03

14

複合的佈局是負責佈置該複合材料的孩子們。因此,如果組合的大小不變,但需要更新組合的相對位置和大小,則可以在組合上調用layout()。但是,如果組合本身的大小或位置需要更新,則必須在其父組合上調用layout()(依此類推,直至到達殼)。經驗法則:如果您添加或刪除了某個控件,或者執行了某些需要重新佈局的操作,請繼續使用該控件層級結構,直到找到具有滾動條的組合並在其上調用layout()。停止使用滾動條的組合的原因在於,其大小不會因響應更改而發生變化 - 其滾動條將「吸收」該滾動條。

請注意,如果需要佈局的更改不是新的孩子或已移除的孩子,則應在致電佈局之前調用Composite.changed(new Control[] {changedControl})

18

與此同時,當我在運行時更改或調整控件層次結構的某些部分時,我更多地瞭解了SWT的缺點。 ScrolledCompositeExpandBar也需要在應該調整其最小或優選內容大小時明確更新。

我寫了一個重新驗證控制層的佈局控制一個小的輔助方法已經改變:

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); 
    } 
} 
3

我剛剛意識到Composite.changed(控制[]子女)。還有就是我幾年前閱讀上的文章:

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

這篇文章還提到調用Composite.layout(布爾改變,布爾全部)來更新佈局:)「調用佈局(是與調用佈局(true)相同,該佈局告訴ColumnLayout在設置子區邊界之前刷新其緩存。「這一切都是正確的,從那以後我一直在做這些事情。但它不是人們想要的,因爲當你想更新佈局時,它基本上會破壞佈局緩存的好處,因爲一個或幾個控件已經改變了需求。

想象一下,您在GridLayout中有一堆StyledText小部件,並且您需要更改其中一個小部件的大小。在StyledText上調用computeSize()非常昂貴。取而代之的是:

錯誤:

parent.layout(true); 

...這所有的孩子呼籲computeSize(),即使他們的要求並沒有改變。你應該這樣做:

右:

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

然後要麼

rootComposite.layout(false, true); 

parent.layout(false); 

不是很直觀。 layout()的參數只是名字不正確。它不應該把它叫做「改變」,而應該叫做「ignoreCache」或其他東西。直觀的事情是在事情發生變化時通過「真實」。相反,您需要傳遞「false」,但在更改()之前無效緩存中已更改的控制。

請注意,調用changed()也會遞歸地使緩存中的父控制它自己的父母,這是完全合理的。所以,當你調用layout()時,你應該在根組合(通常是Shell)上使用all = true來調用它,除非你知道改變後的控件的父級大小將會響應或不能響應。

相關問題