pythin tkinter

老闆要我幫 HW team 的同事開發一個工具,讓他們能比對線路圖。雖說是線路圖,但並不是真的去對圖,而是會先將圖轉為文字檔,再針對這個文字檔來做比對。文字檔的內容會描述線路經過哪些點,這樣實際上是可以自己做,但是問題在於第一次匯出跟第二次匯出的檔案內容並沒有順序性,也因此沒有辦法使用WinMerge之類的文字比對軟體來做。研究過匯出的文字檔內容以後,發覺並不難,只要用 python 很快就能處理完。輸出的結果就以我比較擅長的 HTML + jquery 來做,就可以達到動態的效果,同時也可以跨平台。只是對於 HW team 的同事來說,讓他們老是打指令來產生結果的HTML,是很麻煩的,所以我就在想 GUI 部份要怎麼做。
Python的GUI大致上有以下選擇,其實就涵蓋了主流的幾個知名 Framework:

  • pygtk
  • pyQt
  • wxPython
  • IronPython+Windows form+.Net framework
  • tkinter(tcl/tk)

pygtk、pyqt、wxpython、IronPython都需要安裝額外的runtime library,實在太麻煩,所以後來決定用 Windows python 就有內建的 tkinter 來做。python tkinter 實際上是 tcl/tk 的 binding,我不知道為什麼會包進去,不過既然有,那就方便多了。
教學可以參考PythonInfo 上的 TkInter,如果有碰過 pygtk,那麼,應該是不難。介面也大致跟 Windows 內建的相近,這邊我的心得就是其實可以不用 TopLevel,這會導致多一個多餘的視窗。

window=Tk()
window.title( "my_app" )
window.mainloop() # 直接呼叫 mainloop() 也可以

文字欄位的存取是用 Entry,Entry 內容的存取要透過 StringVar,也就是你要先產生一個 StringVar 物件,Assign 這個物件給 Entry 之後,才能用這個 StringVar 物件來存取。

filename_var=StringVar()
entry=Entry( window, width=100, textvariable=filename_var )
entry.pack()  # 一定要 pack 一下才會出現,要不然你什麼都看不到。
filename_var.set( "Hello" )  # 賦值
print filename_var.get() # 取值

寫到這裡,UI 已經悄然成型,但是字都…好小,找了好久,最後不得已,先產生 global font 物件之後,再一個一個控制項去設定字型:

global_font=("Arial",12)
entry=Entry( window, font=global_font, width=100, textvariable=filename_var )

好了,大致的 UI 有了,那麼怎麼選取檔案,原本以為要自己作一個 Dialog,後來仔細看過官方 TkInter文件之後,發現有提到一個 tkFileDialog,但卻沒提及用法。再根據 python tkFileDialog 關鍵字去找,發現 ActiveState Code上的這篇有使用範例,有了這個再去挖 source code,就可以知道有哪些 method 可以用,我只用到 tkFileDialog.askopenfilename()跟tkFileDialog.asksaveasfilename()。這個 Dialog 的底層是用到 Windows 內建的 Dialog,所以至少介面跟 Windows 接近一致了。

filename=tkFileDialog.askopenfilename( title="Select a file", filetypes=[
( 'JPEG files', '*.jpg' )
] )
output_html=tkFileDialog.asksaveasfilename( title="Save output as...", filetypes=[
( 'HTML files', '*.html' )
] )

dotplurk 筆記

Plurk Api Using C# 沒有提供文件,要自己轉。不過看了原始碼以後,你會發覺轉了也沒用,基本上就是參考 Plurk API
這裡幾點是看了以後的小紀錄:

  • PlurkApi.getPlurks(),傳兩個參數跟傳三個參數是不一樣的。傳兩個參數,使用的是 Polling/getPlurks;傳三個參數,使用的是 Timeline/getPlurks
  • PlurkApi.getResponses()/PlurkApi.getAllResponse() 都是取得某噗的回應,getResponses()可以指定從第幾則開始抓;getAllResponses()則是全部抓,底層是用迴圈搭配getResponses()去抓。
  • 官方 Responses/get 會取回三個部份:friends、responses_seen、responses,PlurkApi 只會傳回 responses 這部份,所以如果要知道 response 是哪個 user,得搭配 PlurkApi.getPublicProfile() 來取得,getPublicProfile()參數是字串,傳回的是 publicProfile,publicProfile 裡有屬性:user_info,可取得 user 資訊。

另外要注意的是,Plurk API有一天 50,000 次的限制,所以使用的時候要注意避免超過限制。

電影流水帳(2010/5/14~2010/5/25)

進度非常緩慢…
話說,Kick-Ass 真的是很容易不小心打成 Kiss-Ass,一下子場面就變成愛情動作片了(誤)~

  • 葉問2(IMDB, Wikipedia)。承續第一集的風格,還不錯看。這一集是描述葉問來到香港開武館以後所遇到的事情,最後則是以打洋人作為收尾,跟第一集比起來,稍嫌沒力了些。剛剛在找連結的時候,才發現釋小龍有演這部片,用 Google 找了圖片之後,才猛然發現真的有釋小龍啊~就是跟黃曉明一起拜師的其中一個,不仔細看,真的是看不出來。
  • Kick-Ass(IMDB, Wikipedia),中譯:特攻聯盟。網路一片好評的電影,果然是不錯看。不錯看的原因,我想是故事與眾不同,而且動作場面也夠力吧。一個平凡人試圖作超級英雄,他出名了,叫 Kick-Ass。想報仇的父女看到新聞正好藉此也扮成超級英雄來對壞蛋下手,結果使得壞蛋把目標設定為 Kick-Ass。為了找出 Kick-Ass,壞蛋的兒子扮成超級英雄,跟 Kick-Ass 聯繫上,混熟以後,吊出這對父女的下落。後來父親因此掛掉,女兒跟 Kick-Ass 聯手報仇,最後是皆大歡喜收場。

電影流水帳(2010/4/29~2010/5/13)

啊啊啊~

  • La môme (IMDB, Wikipedia),中譯:玫瑰人生。這是 Edith Piaf 的傳記片,劇情從她小時候跟著歌女媽媽流浪,到被父親帶到奶奶開的妓院,到跟著父親的馬戲團流浪,到在街頭流浪賣藝,鼎鼎大名的國際巨星,這個法國女人真的是相當的傳奇。前面有些悶,到後來就比較不那麼悶了,故事對於某些地方並不是交代的的很清楚,感覺有些草草帶過。讓我印象比較深刻的地方是,她在孩子的部份其實也走了跟她媽媽一樣的回頭路,疏於對小孩子的照顧,她的媽媽是因此跟她的感情不佳,但她跟她的兒子卻是天人永隔。對於 Marion Cotillard 的印象還停留在 Taxi 系列電影裡,所以看到她在這部片裡的表現,會覺得她真的是很勇敢地擺脫了她既有的形象,而且也惟妙惟肖(應該吧)地扮演了 Edith Piaf,難怪會因此得獎。
  • Looking for Eric(IMDB, Wikipedia),中譯:尋找艾瑞克。蠻不一樣的片,Eric 是郵局員工,本身因為某些緣故拋棄了自己的妻子,導致之後的數十年都活在陰影之下。因為接受了女兒的委託,必須和妻子碰面,他無法面對,所以逆向開車,發生車禍。之後他生命裡出現了另外一個 Eric – Eric Cantona,Eric Cantona 是他所喜愛球隊裡的超級巨星,他倆開始了對談,並且 Eric 因此開始改變自己。這應該是 Eric 自己跟自己的對談,有點像是佛家打禪的意味,自己跟自己深層的意識對話,往往能得到不一樣的體悟。最後 Eric 解決了他家庭裡兩個小孩的問題,也修復跟妻子的關係,皆大歡喜。我覺得蠻有意思的片子。
  • Banlieue 13 – Ultimatum(IMDB, Wikipedia),中譯:暴力特區2。我覺得還可以的動作片,不過我妹嫌這部片不好看,這篇,也是嫌。可能是沒看過第1集,所以看的時候覺得這兩個男主角好厲害,也難怪會拍第二集。

Vimana

Vimana 在 ubuntu 裡所需要的套件大致有這些:libdatetime-perl libexporter-lite-perl libjson-perl libmouse-perl libyaml-perl libapp-cli-perl libfile-type-perl libarchive-zip-perl
HTTP::Lite 則找不到適當的 deb,所以執行 perl Makefile.PL 時,會問說要不要從 CPAN 安裝,這時候要選 y。

==> Auto-install the 1 mandatory module(s) from CPAN? [y] y

接著 make 的時候,就會開始安裝 HTTP::Lite,同時編譯 Vimana
最後輸入 sudo make install,就會開始安裝 Vimana
如果你跟我一樣遇到 make 時,沒反應的話,不妨中斷他,然後輸入 sudo cpan HTTP::Lite 先手動用 cpan 安裝 HTTP::Lite,再重新 perl Makfeile.PL、make、sudo make install 就可以把 Vimana 安裝好了。
安裝 Vimana 以後,首先得用 vimana update 更新套件資料,接著就可以用 vimana install 來進行安裝了。

調整音量

實驗結果發現要讓音量狀態的Widget出現,只要加上 FLAG_SHOW_UI 就行了。
如果要調了以後,出現一個叮的聲音,我想應該只要再加 FLAG_PLAY_SOUND。
能調的東西,可以參考 AudioManager

AudioManager am=null;
int amFlags;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
am = (AudioManager)getSystemService(AUDIO_SERVICE);
amFlags = AudioManager.FLAG_SHOW_UI;
Button button3 = (Button)findViewById( R.id.Button03 );
button3.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
am.adjustVolume( AudioManager.ADJUST_RAISE, amFlags );
}
});
Button button4 = (Button)findViewById( R.id.Button04 );
button4.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
am.adjustVolume( AudioManager.ADJUST_LOWER, amFlags );
}
});
}

電影流水帳(2010/4/21~2010/4/28)

聽說這部片子真的是很不錯,很溫馨又很感人~

  • The Blind Side (IMDB, Wikipedia),中譯:攻其不備。可能是有先看過這篇影評:攻其不備:得獎靠運氣的關係,所以覺得這部片子並不是那麼的好看。這是描述一個家庭如何去幫助一個可憐黑人孩子從默默無聞到一個各大橄欖球隊爭相搶奪的明星球員的故事,我相信在真實世界裡,這個家庭必然經歷了許多衝突,但在電影裡,你真的就只能看到很順理成章地、或輕描淡寫地帶過,讓人覺得就是少了些什麼。
  • Daybreakers (IMDB, Wikipedia),中譯:血世紀。這個故事相當的有意思,故事描述大家都變成了吸血鬼,只剩下少數的人類,吸血鬼都需要血,可是人類的數量又那麼的少,所以基本上只能汲取眷養人類的血液。男主角是個對人類懷有慈悲心的研發替代血液專家,在研究上始終無法突破,某一天他遇到了女主角,於是認識了另外一個由吸血鬼回復成人類的人,開始幫他找出還原成人的原因,後來他找到了,可是自己跟這些倖存的人類也陷入了追殺。最後,是意外發現原來從吸血鬼回復成人類以後,血液也變成了解藥,因此,人類因為被吸血而成為吸血鬼,吸血鬼又無法克制自己吸血,吸了這些人的血以後就又恢復成人,變成解藥,有種巧妙的諷刺感。電影除了這個主梗以外,還有埋下其他有梗的副線劇情,像是兄弟情深、父女衝突等等,算是還不錯看的電影。
  • 聽說 (IMDB, Wikipedia)。這部電影真的是不錯看的愛情小品,天闊與秧秧因為送便當而認識,卻又互以為對方是聽障,就這樣開始了愛情,最後當然是皆大歡喜。不過這個故事如果少了陪襯的林美秀跟羅北安,大概會少了很多樂趣。值得看看的電影。

Python PIL 貼圖

如果我沒找到這篇PIL Tutorial: How to Create a Button Generator的話,我不知道還要走多少冤枉路~總之要貼出透明的效果,要在 paste() 時把要貼的那張圖當作第3個參數傳進去,這樣出來的效果就是對的!

# 從指定目錄拿三張圖片出來做小圖,第1張傾斜10度,第3章傾斜-10度,然後在貼到一起,做出類似撲克牌或紙疊在一起的效果。
import glob
import Image
def createThumbnail( filename ):
im = Image.open( filename )
im.thumbnail((96,96), Image.ANTIALIAS )
newImage = Image.new( "RGBA", (144,144) )
newImage.paste( im, (16,16) )
return newImage
for dir in sys.argv[1:]:
files = glob.glob( os.path.join( dir, "*.jpg" ) )
im0 = createThumbnail( files[0] ).rotate( 10 ).crop( ( 0, 0, 128, 128 ) )
im1 = createThumbnail( files[1] ).crop( ( 0, 0, 128, 128 ) )
im2 = createThumbnail( files[2] ).rotate( -10 ).crop( (0, 0, 128, 128 ) )
im0.paste( im1, ( 10, 0 ), im1 )  # 關鍵!!
im0.paste( im2, ( 20, 10 ), im2 )# 關鍵!!
im0.save( "out.png")

Trace WebView.loadUrl

為了想知道 Android 到底使用哪個 proxy 設定,所以只能往下追了。
WebView.loadUrl( String url ) 送 message (LOAD_URL) 給 WebViewCore
WebViewCore.transfermessages() 收到以後呼叫 loadUrl( String url )
loadUrl() 呼叫 BrowserFrame.loadUrl()
BrowserFrame.loadUrl( String url ) 如果 url 是 javascript: 開頭的,丟給 javascript engine,一般情況則是呼叫 nativeLoadUrl( url )
nativeLoadUrl() 位於 WebCoreFrameBridge.cpp 裡,根據 JNI 函數對照表,對應到的是 loadUrl()。loadUrl() 則先依照 url 建立 ResourceRequest 物件,再傳入 pFrame->loader()->load() 裡。
pFrame 真正的身份是 external/webkit/WebCore/page 下的 Frame,裏面的 loader() 真實身份則是 external/webkit/WebCore/loader/FrameLoader。
接下來可以參考 http://trac.webkit.org/wiki/CodePaths 最後一項: Get data from network。
稍稍不一樣的是,Android 使用 external/webkit/WebCore/platform/network/android 下的 ResourceRequest、ResourceHandleAndroid…等類別,而非一般的 soup 或是 curl。
我幾乎可以確定應該是 ResourceHandleAndroid 類別負責真正的下載工作,但我卻看不懂裏面是怎麼呼叫的,裏面使用了相當迂迴的方法來呼叫。
以 network/curl/ResourceHandleCurl 來說,裏面就很清楚的用到 curl library,network/qt/ResourceHandleQt、network/soup/ResourceHandleSoup 也是如此。
今天就先看到這裡吧。

xargs

以前就看過 xargs 這指令了,不過那時只有看人家的範例,沒有理解為什麼要這樣用。等到想試著用的時候,才發現原來是這樣子。
因為我之前完全誤解了。
舉例來說,這樣的命令:

ls | xargs echo

假設我目前目錄有 file0, file1, file2 這3個檔案,我以為 xargs 會根據 stdin,執行 echo 三次,這當然是錯誤的。
xargs 會讀取 stdin 的內容,然後轉成以空白分格的字串,再將結果作為指定命令的參數。所以上面最後會執行的指令其實是:

echo file0 file1 file2