網(wǎng)店的Logo。那大腿不是別人的,正是韓國歌星寶兒……
她跟我說上面這張圖最大的問題就在于太有夜店風格,與她的店不符。不過用著用著,她自己倒也喜歡上了。
這個是剛出爐的5月新款的預告,照片里的人可全是她……
Jasper's Java Jacal
嘉士伯的Java小屋
|
|
BlogJava |
首頁 |
發(fā)新隨筆 |
發(fā)新文章 |
聯(lián)系 |
聚合![]() |
隨筆:51 文章:2 評論:717 引用:0 |
前文說道開發(fā)一個Gadget可以分為兩個步驟:先寫界面的XML文件,再寫邏輯部分的JavaScript。我們就遵循這個步驟來寫一個再簡單也不過的Gadget。 用到的工具有兩個,一個是隨Google Desktop SDK附帶的Gadget Designer,用來編寫并有限的預覽界面,還可以調(diào)試JavaScript(這個就更有限了);一個是Google Desktop,用來測試寫好的Gadget。下面要寫的例子是我在為某研究院某個項目策劃階段作POC時所寫的一個小例子,可以顯示一個Google用戶的Picasa相冊中的Album名稱和縮略圖。雖然很小,但包含了Google賬戶的自動登錄,顯示網(wǎng)絡圖片,XmlHttpRequest的使用等很多實用技巧。整個完成之后是這個樣子: 請跟我一起來。現(xiàn)在打開Gadget Designer,選擇File->New Gadget,輸入了名稱“Picasa”之后,就可以看到一個完整Gadget的雛形了。你可以找到這個項目所在的文件夾,雙擊其中的gadget.gmanifest,此時如果你已經(jīng)安裝了Google Desktop,就可以看到Desktop自動啟動,并把這個很“白”的Gadget(別笑,除了一張白色背景圖片以外,確實什么也沒有)顯示在Sidebar中。如圖: 到項目文件夾里可以看到一個main.xml文件和一個main.js文件。我們的界面就是在main.xml文件里指定的,打開它,可以看見它指定了一張GadgetDesigner幫我們生成的白色png圖片作背景,還指定了我們要導入哪些個.js文件。我們來小改兩個地方: <view height="150" width="250" onopen="view_onOpen()">
<img src="stock_images\background.png" /> <script src="main.js" /> </view> 一是把view的height改成250,二是給img元素添加一個屬性name并給一個值,就像這樣: <img name=”bgImage” src="stock_images\background.png" />
然后雙擊gadget.gmanifest,看看更改效果: 乍一看貌似沒什么改變,但是注意看我用黑色線圈出來的那一條橫杠,那是我們的Gadget的下邊沿,說明它的高度還是變化了,但是白色的背景沒有變,因為我們沒有改變背景圖片的大小。現(xiàn)在通過.js文件中代碼的方式來改變背景圖片的高度,可以看出些有意思的東西。 打開main.js文件,你應該會看到一個view_onOpen()函數(shù),這就是Gadget啟動時會自動調(diào)用的第一個函數(shù)(好吧,并不嚴格,但是在調(diào)用的順序上,它的確是相當靠前的),我們就在這個函數(shù)內(nèi)部添加下面這一句: bgImage.height=250;
再雙擊gadget.gmanifest運行看看,白色背景也變高了吧。 我知道你一定會問,代碼里的bgImage是什么東西?怎么沒見在任何地方聲明這個變量,也沒見任何地方作初始化呢?回想我們剛才在main.xml文件里做了什么?我們給背景圖片取了一個名字,叫bgImage,而且別懷疑,你在代碼里訪問的這個bgImage,正是那張圖片!背后的工作就是Gadget Host通過JavaScript引擎為我們做的,凡是在.xml文件里放置的東西(無論什么,圖片也好,按鈕也好,一個抽象的div也好),只要你給了一個name屬性,在JavaScript代碼中就可以直接使用這個名字來訪問該對象(前提是你給的名字得是獨一無二的),這與瀏覽器中隨時可以訪問document對象而不用做任何聲明一樣,那是瀏覽器這個運行環(huán)境提供的對象,隨時可用。 另一個值得注意的地方是在.xml文件里,屬性的值都必須加上引號,像height=”250”(因為那里使用的是標準的xml語法),而在JavaScript代碼中,就要根據(jù)屬性具體的類型來決定,像高度這種整數(shù)型的值,就不用加。 你可能還會問,那么bgImage這個對象,是什么類型的,它有些什么屬性和方法可供我使用呢?它是一個img類型的對象,參考http://code.google.com/intl/zh-CN/apis/desktop/docs/gadget_apiref.html這個鏈接,這也是Google Desktop Gadget的API參考頁面,列出了Gadget Host提供的各種對象屬性和方法的說明(雖然事實驗證,Google自己列的這些都不全面,后話)。 最后叮囑一句:盡管main.xml文件里的東西(什么img啊,以后還會加進div啊,checkbox之類的東西)看起來多么的像HTML,Gadget都和Web沒有天然的聯(lián)系。Google自己發(fā)布了一些Gadget,例如Gmail和Google Docs,外觀與這兩個服務的網(wǎng)頁非常像,再加上Gadget也主要使用JavaScript開發(fā)(也少不了Universal Gadget跟著摻合),間接導致了總有人把Gadget顯示的地方考慮成一個小的瀏覽器窗口,而想把Web的一些東西簡單的放在這里,到底行不行呢?李寧說:一切皆有可能。阿迪說:沒有不可能。匹克說:我能,無限可能。我要說:可能,但很難(笑)。 所以在編寫Gadget的時候,最好的方法是把它當成純粹的桌面程序,忘掉Web的那一套。 這一節(jié)給大家入個門,下一節(jié)開始說說在Gadget中怎么做Google帳戶的登錄,還會很羅嗦的,請見諒(笑)。
在Gadget開發(fā)人員看來——我當然是指你我這樣的IT民工,來開發(fā)一個Gadget的人,而不是Google大樓里成天琢磨怎么和微軟對著干的那幫子人——一個Gadget由三大部分組成:描述UI的一系列.xml文件;存放程序邏輯的.js文件以及資源。 下面是一個Gadget項目在Google Desktop Disigner里面的結(jié)構(gòu)截圖。
資源這東西好理解,無非是程序要用到的各種圖片啦,字符串啦等等。讀者:字符串?什么意思?答:把程序會用到的一系列字符串統(tǒng)一存放,想引用的時候使用一個常量名字就可以,而不必在需要這些字符串的地方每次都重寫一遍,和Java中的property文件作用類似。 其余的兩部分會分節(jié)來詳細講解。 當然說只有三部分,是指我們大多只關(guān)心這么多,實際上還有第四部分,一個Gadget Settings文件,其中大多是關(guān)于這個Gadget的元信息,什么作者啊,創(chuàng)建日期啊,uuid啊,戶口所在地啊,最高學歷啊,婚姻狀況啊,哦,我給說成簡歷了(笑)。 前面也說到過,一個Gadget其實就是一個桌面應用程序(再一次的,不管寫起來某些語法多么得像HTML,Gadget與Web都沒有天然的聯(lián)系),只不過這個程序在Gadget Host的管理之下,行話叫“托管”。Windows下沒有單獨的Gadget Host,它被合并在Google Desktop里面(算是另一種捆綁吧)。而Linux下的確有干干凈凈的Gadget Host,且有源碼下載,我們所有對Gadget的理解也都源于這個版本和相關(guān)的文檔。 那么在Gadget Host看來,一個Gadget是什么東西呢? 以我寫的一個小Picasa Gadget為例,在Picasa Gadget初次加載之前,它是一個.gg的壓縮包(其實就是一個標準的zip包,被改了后綴名而已),Gadget Host會從中讀取需要的文件,然后做相應的解釋。 Gadget Host可以看成只有兩部分組成:一個UI的渲染器和一個JavaScript引擎。 說UI渲染器之前就不得不回頭重提剛才說到的一個Gadget包括了一系列.xml文件這件事。實際上這些.xml文件就是用來指定你想寫的Gadget的界面的,就是說,你的Gadget跑起來以后長成什么樣子,是由這些個.xml文件來決定的(當然,嚴格說來可以使用JavaScript在運行時改變一些內(nèi)容,但請不要抬杠,笑)。 這些.xml文件中最主要的是main.xml這個文件,你的Gadget窗口有多大,在什么位置有幾個按鈕,列表有沒有滾動條,背景是什么顏色等等,都在這里指定。還包括這些東西上的事件監(jiān)聽函數(shù)也一并在這里聲明(不知為何,讓我莫名的想起微軟的MFC,當然,嚴格說來可以使用JavaScript在運行時動態(tài)改變這些內(nèi)容,但請不要再次抬杠,笑)。 UI渲染器干什么呢?就是來把這個.xml所要求的界面轉(zhuǎn)換成具體的系統(tǒng)調(diào)用,讓操作系統(tǒng)來完成繪圖(好吧好吧,你喜歡嚴格,那我告訴你,Linux版本下首先被轉(zhuǎn)換為Qt的C++類,由Qt來發(fā)起對系統(tǒng)繪圖的調(diào)用)。 既然Gadget的程序邏輯都使用JavaScript來編寫,理所應當?shù)模珿adget Host必然要包含一個JavaScript解釋器來解釋這些代碼,這個解釋器也被叫做JavaScript引擎。Gadget Host里確實有這么個東西,叫做Spider Monkey,它恰好也是FireFox所使用的JavaScript引擎。廣義上說,一個引擎的作用主要是解釋它遇到的一切JavaScript代碼,如果代碼使用到核心JavaScript的功能和對象,它便直接提供;如果代碼使用到了一些依賴于底層的對象(例如Gadget Host就提供了很多專有的JavaScript對象和方法供使用,這些都是核心JavaScript之外的東西),則引擎還要負責轉(zhuǎn)發(fā)這樣的請求(你可以說,這實際上是適配器做的事,我這樣簡化有助于理解,請不要一再抬杠,笑)。 也可以這樣從邏輯上看Gadget的組成:即一個Gadget就是一組圖形界面,加這些界面上每個控件(按鈕啊,列表啊,輸入框等等)的事件監(jiān)聽函數(shù),這種界面描述與事件邏輯分離的程序模型,和微軟的XAML+C#簡直如出一轍。因此一個Gadget的開發(fā)實際上也就可以分為這兩大步驟:先寫界面的XML文件,再寫邏輯部分的JavaScript。下面一節(jié)就用一個小例子來看看具體如何做。別嫌我說得太詳細哦。 去年這一年被研究生院和所里揪著干了不少自己并不擅長的事,其中就包括為各種大小活動設計PPT,邀請函,節(jié)目表之類的東西。年底了,拿出來看看也能理一理自己從無到有,從門外漢到菜鳥的成長過程。共賞,共析哈。 最早的一張,元旦晚會時為模特隊做的。本來他們自己做了一套共計3張的PPT,趕巧我這張已經(jīng)做好了,便讓他們自己選,結(jié)果還是選了我的,呵呵。
同一場晚會為舞蹈隊做的,沒太多東西,只是字體和配色斟酌了一陣子。
青年博客大賽決賽頒獎晚會的主題PPT,剛提交第一版便遭到老師表揚,結(jié)果一點修改都沒有做便獲通過。
同一場晚會的領導致辭圖,風格還挺一致的吧?(笑)
仍然是博客大賽決賽頒獎晚會,那一次晚會因為外請節(jié)目比較多,整體水平著實不低呢。
計算所青年歌手大賽的節(jié)目單,其實參考了很有名氣的設計,所以才能做成這個樣子,不敢專美,特此聲明。
計算所青歌賽的主題PPT,多虧有設計的四大原則幫忙啊。后來一個計算所的師兄還問我把這張片子討了去,說是只看一眼就喜歡上了里面的女孩,還一個勁的問我她是誰,是咱所的么,我趕緊解釋說不是不是……
最近一次為街舞社的表演做的PPT,發(fā)現(xiàn)自己的風格算是定型了,怎么看都似曾相識,當然也可以說,是黔驢技窮了……
按:系列文章,將談及Google Gadget的體系結(jié)構(gòu)和開發(fā)入門,后期還會有和類似技術(shù)Mozilla Prism的對比。
開始之前先澄清一件事,這里所說的Gadget實際上是指Google Desktop Gadget,而不是指在iGoogle或者FaceBook上運行的Gadget,那個叫做Universal Gadget。 細說起來,其實Gadget和Universal Gadget不僅名稱不同,在實現(xiàn)上也完全是兩回事。從使用者的角度看,Univeral Gadget就是一個HTML的頁面,只不過在顯示的時候是實時從iGoogle之類的容器網(wǎng)站上下載過來并展現(xiàn)在一個iframe里面的。而Desktop Gadget則是一個不折不扣的桌面應用程序(雖然運行在Google Desktop這個容器中)。 從開發(fā)人員的角度看,Universal Gadget是一個JavaScript文件和XML文件的集合,由容器網(wǎng)站(例如iGoogle,Facebook等等)來渲染成HTML頁面并呈現(xiàn)給最終用戶。在一個Universal Gadget中使用的技術(shù)都是標準的Web技術(shù),其能量也限制在瀏覽器的框架中。 而在開發(fā)一個Desktop Gadget時,雖然也使用XML文件來指定程序的UI,使用JavaScript來實現(xiàn)程序的邏輯,但與Web或者瀏覽器都沒有天然的聯(lián)系,說是完全的另一套程序開發(fā)體系也不為過(使用的XML語法與Universal Gadget不同,能夠使用的JavaScript的對象及功能也不同)。 但另一方面的情況導致兩者時常被人混為一談,那就是,一個Universal Gadget是可以被加載到Desktop Gadget的面板中并正常運行的(嚴格的說只有一部分),而一部分Desktop Gadget也可以加載到iGoogle網(wǎng)站中運行(因而使它看上去像一個Universal Gadget,當然需要系統(tǒng)已安裝了Google Desktop才可以)。 書歸正傳,下面就來說Gadget到底是什么,以及它的體系結(jié)構(gòu)和背后思想。 (注:以下如果沒有特別指明,提起Gadget全都是指Desktop Gadget,而iGoogle上的Gadget會指明為Universal Gadget)
Java號稱對Unicode提供天然的支持,這話在很久很久以前就已經(jīng)是假的了(不過曾經(jīng)是真的),實際上,到JDK5.0為止,Java才算剛剛跟上Unicode的腳步,開始提供對增補字符的支持。
現(xiàn)在的Unicode碼空間為U+0000到U+10FFFF,一共1114112個碼位,其中只有1,112,064 個碼位是合法的(我來替你做算術(shù),有2048個碼位不合法),但并不是說現(xiàn)在的Unicode就有這么多個字符了,實際上其中很多碼位還是空閑的,到Unicode 4.0 規(guī)范為止,只有96,382個碼位被分配了字符(但無論如何,仍比很多人認為的65536個字符要多得多了)。其中U+0000 到U+FFFF的部分被稱為基本多語言面(Basic Multilingual Plane,BMP)。U+10000及以上的字符稱為補充字符。在Java中(Java1.5之后),補充字符使用兩個char型變量來表示,這兩個char型變量就組成了所謂的surrogate pair(在底層實際上是使用一個int進行表示的)。第一個char型變量的范圍稱為“高代理部分”(high-surrogates range,從"uD800到"uDBFF,共1024個碼位), 第二個char型變量的范圍稱為low-surrogates range(從"uDC00到"uDFFF,共1024個碼位),這樣使用surrogate pair可以表示的字符數(shù)一共是1024的平方計1048576個,加上BMP的65536個碼位,去掉2048個非法的碼位,正好是1,112,064個碼位。 關(guān)于Unicode的碼空間實際上有一些稍不小心就會讓人犯錯的地方。比如我們都知道從U+0000到U+FFFF的部分被稱為基本多語言面(Basic Multilingual Plane,BMP),這個范圍內(nèi)的字符在使用UTF-16編碼時,只需要一個char型變量就可以保存。仔細看看這個范圍,應該有65536這么大,因此你會說單字節(jié)的UTF-16編碼能夠表示65536個字符,你也會說Unicode的基本多語言面包含65536個字符,但是再想想剛才說過的surrogate pair,一個UTF-16表示的增補字符(再一次的,需要兩個char型變量才能表示的字符)怎樣才能被正確的識別為增補字符,而不是兩個普通的字符呢?答案你也知道,就是通過看它的第一個char是不是在高代理范圍內(nèi),第二個char是不是在低代理范圍內(nèi)來決定,這也意味著,高代理和低代理所占的共2048個碼位(從0xD800到0xDFFF)是不能分配給其他字符的。 但這是對UTF-16這種編碼方法而言,而對Unicode這樣的字符集呢?在Unicode的編號中,U+D800到U+DFFF是否有字符分配?答案是也沒有!這是典型的字符集為方便編碼方法而做的安排(你問他們這么做的目的?當然是希望基本多語言面中的字符和一個char型的UTF-16編碼的字符能夠一一對應,少些麻煩,從中我們也能看出UTF-16與Unicode間很深的淵源與結(jié)合)。也就是說,無論Unicode還是UTF-16編碼后的字符,在0x0000至0xFFFF這個范圍內(nèi),只有63488個字符。這就好比最初的CPU被勉強拿來做多媒體應用,用得多了,CPU就不得不修正自己從硬件上對多媒體應用提供支持了。 盡管不情愿,但說到這里總還得扯扯相關(guān)的概念:代碼點和代碼單元。 代碼點(Code Point)就是指Unicode中為字符分配的編號,一個字符只占一個代碼點,例如我們說到字符“漢”,它的代碼點是U+6C49。 代碼單元(Code Unit)則是針對編碼方法而言,它指的是編碼方法中對一個字符編碼以后所占的最小存儲單元。例如UTF-8中,代碼單元是一個字節(jié),因為一個字符可以被編碼為1個,2個或者3個4個字節(jié);在UTF-16中,代碼單元變成了兩個字節(jié)(就是一個char),因為一個字符可以被編碼為1個或2個char(你找不到比一個char還小的UTF-16編碼的字符,嘿嘿)。說得再羅嗦一點,一個字符,僅僅對應一個代碼點,但卻可能有多個代碼單元(即可能被編碼為2個char)。 以上概念絕非學術(shù)化的繞口令,這意味著當你想以一種統(tǒng)一的方式指定自己使用什么字符的時候,使用代碼點(即你告訴你的程序,你要用Unicode中的第幾個字符)總是比使用代碼單元更好(因為這樣做的話你還得區(qū)分情況,有時候提供一個16進制數(shù)字,有時候要提供兩個)。 例如我們有一個增補字符???(哈哈,你看到了三個問號對吧?因為我的系統(tǒng)顯示不出這個字符),它在Unicode中的編號是U+2F81A,當在程序中需要使用這個字符的時候,就可以這樣來寫: String s=String.valueOf(Character.toChars(0x2F81A));
char[]chars=s.toCharArray(); for(char c:chars){ System.out.format("%x",(short)c); } 后面的for循環(huán)把這個字符的UTF-16編碼打印了出來,結(jié)果是 d87edc1a 注意到了嗎?這個字符變成了兩個char型變量,其中0xd87e就是高代理部分的值,0xdc1a就是低代理的值。 |
|