要建立一個 Image,最直接了當的用法是給它 url:
Image img = new Image("http://an.url/pic.jpg");
這裡的 url 使用相對路徑亦可,不過得注意是相對於載入這個 GWT module 的頁面就是了。
切到這個 Image(String) 這個 constructor,會發現當中做了兩件事情:
- 將 state 設定為新產生的 UnclippedState 物件
- 設定 style name 為 "gwt-Image"
設定 style name 這檔子事情有點無關緊要,忽略不管。至於 state 這個 field 是怎麼一回事?這似乎得要回頭看開頭 JavaDoc 寫的:
「The image can be in 'unclipped' mode (the default) or 'clipped' mode.」也就是說,Image 透過 state 來決定當下是哪一種使用方式,這可以解釋為甚麼有另一個 Image(String, int, int, int, int) 的 constructor。實際去看 Image 的 method 行為,getter、setter、onLoad() 等都是由 state 負責,只有跟 event handler 有關的 method 是用 Widget.addHandler() 處理。
於是找到 Image 裡頭 State 這個 private 的 abstract class。它只有兩個 method 不是 abstract 的:onLoad(Image)、fireSyntheticLoadEvent(Image),這兩個都跟 event 有關,在這篇文章當中先略過,以免枝節太多。其餘的 abstract method 留給 ClippedState、UnclippedState 實做。
比對 ClippedState 與 UnclippedState 實做 method 的差異,差別在於 ClippedState 多了 width、height、left、top 這幾個 field,UnclippedState 在取這些值時,是直接對 Image 所屬的 ImageElement 取值,而 ClippedState 則直接回傳 field 的值。另外,如果叫用到 ClippedState.setUrl() 會將 state 切換到 UnclippedState;反之,如果叫用到 UnclippedState.setVisibleRect() 與 setUrlAndVisibleRect() 會將 state 切換到 ClippedState。
這到底在幹什麼?
回歸實際用途,ClippedState 的目的是只顯示圖片上的某個矩形區塊,所以得加上長、寬、起始位置等資訊。製造出這種效果的方法,則是靠 CSS 設定 span 的 background 來辦到。怎麼知道的呢?答案在 constructor 當中的這行:
image.replaceElement(impl.createStructure(url, left, top, width, height));
先用 ClippedImageImpl.createStructure() 製造出一個 Element 物件,然後再把原本 Image 的 element 換成這個。再仔細看一下 ClippedImageImpl 裡頭的寫法,發現它直接用最硬幹的方式設定 element 的 HTML 與 style,也難怪會抽出去自成一個 class。這說明了為甚麼 JavaDoc 強調當 clipped 與 unclipped 互換時,所有的 style 設定都會消失。
重新回到 Image,會發現這個 class 只是邏輯上的存在,為了做到 clipped/unclipped 的效果,所以透過 State 來處理;因為底層實做方式的不同,所以當物件的行為模式轉換時變更到對應的 state。而真正對應 DOM,則是 ImageElement(unclipped mode)與 SpanElement(clipped mode)。使用 Image 時哪會想到底下這麼多怪東西?好的 class 如當是也......
Image 最後還有一個 perfetch(String) 的功能,就留待下回分解了(?)
這篇是退伍後的復健治療... 所以... [遮臉]