2016年5月9日 星期一

GXT Component 的 onLoad 與 onShow 時機點

最近想要在 UI component 出現 / 消失的時候自動做一些事情,於是打算從 GXT Component 下手。不過怎麼寫怎麼有問題,只好寫 n 個 SSCCE 來確認一下,實驗結果紀錄於此。

基本認識

我關心這四個 method:

  • onLoad()
  • onUnload()
  • onShow()
  • onHide()

onLoad()onUnload() 是從 GWT 的 Widget 就定義的 method。理論上跟 onAttach()onDetach() 等意,就是這個 component 加入到 DOM(或是從 DOM 中移除)時會觸發的 method。不過 API 都強烈建議用 onLoad()onUnload() 了,就乖乖照辦。

onShow()onHide() 是 GXT Component 開始定義的 method,最常遇到的 caller 大概是 GXT Component 的 setVisible()(override UIObject)。

測試環境

  • JDK 1.7
  • GWT 2.7
  • GXT 3.1.0
  • Windows 7 (64bit)
  • Chrome 50

測試方式

我製造了兩個 component FooButton(繼承 TextButton) 跟 FooCP(繼承 ContentPanel)。分別 override 上述四個 method,例如:

    @Override
    protected void onLoad() {
        super.onLoad();
        Console.log("load " + getText());
    }

會需要 FooCP 是因為 AccordionLayoutContainerBorderLayoutContainer(在某些情況下)要求 child 是 ContentPanel

基本上我是用 UiBinder 撰寫 TestLayout(btw… TestLayout 繼承的是 GXT 的 Composite),然後 entry point 的 onModuleLoad() 這樣寫:

    Viewport vp = new Viewport();
    vp.add(new TestLayout());
    RootPanel.get().add(vp);

主要就是測試 FooButtonFooCP 作為各 layout container 還有 GXT TabPanel(見一次 murmur 一次,為啥這東西不是 container… ==”)的 child 時,上述四個 method 是否會觸發。

component 的行為(例如 collapse、close tab…)都是實際 UI 操作而不是程式呼叫 method。(希望這個差異不會炸出什麼新的問題)。

測試結果

注意:沒有測試所有已知的 layout container。

毫無反應區

下列 container 只會觸發 onLoad(),不會觸發 onShow()

  • AccordionLayoutContainer
  • CenterLayoutContainer
  • ContentPanel
  • FieldLabel
  • FieldSet(有設定 collapsible=true
  • FlowLayout
  • HBoxLayoutContainer
  • HorizontalLayoutContainer
  • NorthSouthContainer
  • SimpleContainer
  • VBoxLayoutContainer
  • VerticallayoutContainer

BorderLayoutContainer

center 的 child 只會在初始時觸發一次 onLoad(),其餘操作均無反應。

其他四個 region 在初始時會先依序觸發 onLoad(),然後再依序觸發 onShow()三次(如果不是用 UiBinder,而是用 Swing 的方式直接掛一個組好的 BorderLayoutContainerViewport,就會變兩次….. WTF?)

當某個 region 被 collapse 時,該 component 會觸發 onUnload()、但是不會觸發 onHide()。接著,其他還顯示的 region 會依序觸發 onShow()

當某個已經 collapse 的 region 展開回原狀時,會先觸發它的 onLoad(),然後再依序呼叫全部 region 的 onShow()

當某個已經 collapse 的 region 以 float 的方式出現 / 消失時,會觸發 onLoad() / onHide(),但是不會觸發其他 region 的 method。

當某個已經 collapse 的 region 以 float 的方式出現,然後再按下展開回原狀的按鈕,看起來是:

  1. 做 float region 消失的程序
  2. 做 region 恢復的程序

感覺有優化的空間

CardLayout

一開始會觸發所有 child 的 onHide(),然後才觸發 onLoad(),最後才是觸發 active widget 的 onShow()

切換 active widget 時,就是觸發對應 child 的 onShowonHide

TabPanel

(再 murmur 一次,為啥這玩意不是 layout container ==”)

初始時的觸發順序

  1. active widget 的 onHide()
  2. active widget 的 onShow()
  3. 其他 child 的 onHide()
  4. 全部 child 的 onLoad()

以下假設目前的 active widget 是 Foo1,另外還有一個 Foo2

  • 將 active widget 切換為 Foo2
    1. 觸發 Foo1onHide()
    2. 觸發 Foo2onShow()
  • 關掉有 Foo2 的 tab:
    1. 觸發 Foo2onUnload()
    2. 觸發 Foo2onShow()
  • 關掉有 Foo1 的 tab:
    1. 觸發 Foo1onUnload()
    2. 觸發 Foo1onShow()
    3. 觸發 Foo2onShow()

簡單地說,被關掉的 child 都會先觸發 onUnload() 然後再觸發 onShow()(WTF?)

結論(X) 詰譙(O)

其實不知道要有什麼結論… Orz

AccordionLayoutContainerFieldSet 並不會觸發 onShow() / onHide(),這點還可以接受。

CardLayoutContainer 的初始化步驟非常怪,都還沒掛上 DOM 那觸發 onHide() 是要幹麼?但是初始化只有一次,所以就算了。

BorderLayoutContainer 的 collapse 行為跟 onHide() 一點關係也沒有,但是會觸發其他 region 的 onShow()

TabPanel 可能是集各種詭異於一身的… 對,他還不是 container(謎之聲:你是要講幾次?)。關掉一個 tab 會觸發 onUnload() 這完全合情合理,但是為什麼還會再觸發 onShow() 阿阿阿阿…… Orz

我很願意相信,這背後都有好理由來支撐這一堆詭異行為;只是我更希望能有統一的行為模式,雖然會關心到這種 detail 程度的時候好像不多…

可是我就需要阿... [淚目]

3 則留言:

  1. 這看起來要 trace javascript code 才能看到全貌

    回覆刪除
  2. 不用耶... 因為基本上都已經包成 Java 的樣子了

    回覆刪除
  3. Much as they do with numbers in roulette, the betting right here is focused on guessing an outcome. Both the player and the banker are dealt two playing cards face up. If either 온라인카지노 the player or banker has a hand totaling eight or nine, it’s called a natural win. The hand ends and the gamers who bet on the best facet get paid even cash.

    回覆刪除