:::

圖片上傳與Plurk貼圖的好工具:ZScreen與ImageShack

布丁布丁吃布丁

圖片上傳與Plurk貼圖的好工具:ZScreen與ImageShack

image

我習慣於用Plurk來寫個圖文兼具的噗,而Plurk中要貼圖必須要先上傳、取得網址才能完成這個任務,操作手續繁雜。再者Plurk內建的圖片伺服器並沒有提供像ImageShackFlickr這種專門為圖片、影片典藏網站一樣的管理介面,上傳之後就無法再管理,要取得舊有圖片也是不方便。

後來我發現可以使用ZSCreen這個強大的工具來解決上述的問題,讓我可以快速地截圖、上傳圖片到指定的網站(如ImageShack)、並且方便地將圖片連結放到剪貼簿中。

Plurk貼圖之不便

你有在使用Plurk寫微網誌嗎?我非常習慣於使用Plurk來記錄事物,像是一邊寫論文的程式,一邊記錄一下現在做到哪裡、狀況如何、下一步該做些什麼。這樣能夠讓我方便日後將這些零碎的資訊彙整起來撰寫成一篇較為完整的Blog。

image

Plurk的特色在於可以在簡短的140字中提供圖文兼具的內容,只要貼上圖片的網址,最後即能顯示圖片的縮圖,別人也能點選縮圖看到更大的圖片。上圖即是早上我分享Astrid小章魚待辦事項工具的更新消息,貼個小章魚圖片可以讓同樣使用這個軟體的同好更容易發現這消息。

image

說實在的,Plurk的貼圖功能實在是不好用。首先要先從「分享 > 圖片」中打開「分享圖片」的對話視窗,選擇檔案,按下「上傳圖檔」,等待圖片上傳,然後再繼續寫你想要寫的內容。

其實這個動作最終目的也不過就是要取得一個圖片上傳的網址,但是這些等待動作卻可能會打斷寫作的思緒。

另一個問題在於利用原本的上傳功能上傳到Plurk的圖片伺服器之後,使用者就沒辦法管理那些已經上傳的圖片,而圖片也會被強制縮圖、無法展現原本的大小。他不像ImageShack或Flickr這種圖片或影片典藏網站一樣具備豐富的管理功能,使用者更無法回溯以前自己上傳的圖片。這對像我這種利用Plurk記錄生活點滴的使用者來說是非常不方便的缺點。

因此,我需要透過第三方的服務來協助我典藏圖片與上傳圖片。我使用的圖片典藏網站是ImageShack,而圖片上傳工具就是本篇的主角ZScreen了。

ZScreen簡介

由於重灌狂人介紹了ZUploader這個好用的圖片、檔案、文字上傳軟體,連帶地也讓我發現了ZScreen這個比ZUploader更為強大的工具。

ZScreen功能不僅具備原本ZUploader可以做到的上傳功能,還有各種豐富的功能可以使用。第一次開啟來使用時,我在SCreen的複雜介面中摸了好久才知道個大概,甚至有部分功能是看了網路上簡睿隨筆的ZScreen:一氣呵成的單鍵「抓圖與傳檔」工具才知道原來還有短網址功能。

image

ZScreen還有一個很重要的功能,除了可以用匿名身分上傳之外,還可以用已註冊會員的身分上傳到目標位置,包含FTP、本地端主機、RapidShareSendSpaceFlickrImageShackTinyPicTwitterImageBarnMindTouch等你可能聽過也可能沒聽過的空間。這個功能讓我們可以方便地將圖片上傳到自己慣用的圖片典藏網站中,已方便進行圖片的管理。

免費圖片、影片典藏網站:ImageShack

image

這隻黃色樹蛙是老牌多媒體典藏網站ImageShack的招牌圖示。ImageShack的特色在於免費、穩定、上傳無限空間、提供圖片直接連結(這樣子才能在Plurk上顯示,而不是一定得連到該網站才能開啟圖片),他也有很多第三方工具來協助上傳,像ZScreen就是這類型的工具之一。

image

註冊免費會員之後,使用者可以利用「My Images」功能方便地管理上傳的圖片、影片,而沒有像Flickr免費會員只能看200張的限制。根據使用條款的說明,註冊會員的圖片將會永久保存而不會被刪除。當然,前提是不要觸犯暴力及色情的使用條款限制。

我現在多使用ImageShack來保存圖片,而在以下ZScreen介紹中也是使用ImageShack作為上傳圖片的目的地。如果看到這邊你也覺得很有興趣的話,歡迎點此註冊一個免費會員來玩玩!

設定ZScreen上傳到ImageShack

安裝ZScreen、註冊ImageShack的操作不難,但是要在ZScreen介面中設定上傳目的為ImageShack,則需要摸索一陣子。我假設正在看這篇文章的你已經安裝了ZScreen,也已經註冊了ImageShack,那麼接下來就是教你怎麼在ZScreen裡面進行設定。

取得ImageShack的Registration code

image

ZScreen必須設定你在Image Shack的User Name(使用者名稱)跟Registration Code(註冊碼)。User Name在註冊的時候你應該已經設定了,不過Registration Code則是要註冊完畢之後到My Images –> Preferences(偏好設定)裡面才能查詢。其中「My ImageShack Registration Code」底下的表單則是Registration Code,看起來就像是一串很長的亂碼。

選擇ZScreen上傳目的為ImageShack

image

請打開ZScreen的主介面「Main」,並在「Destinations」的「Images:」中選擇「ImageShack – www.imageshack.us」。

設定ZScreen中的ImageShack

image

一樣是在ZScreen的視窗中,從上排導覽頁中選擇「Destination」,再從次導覽列中選擇「ImageShack」。你會看到ZScreen需要你填入Registration Code跟User Name,請你將ImageShack中的資料填入即可。

如此設定完畢之後,透過ZScreen上傳圖片資料就會自動傳到ImageShack囉。

使用ZScreen擷取、上傳圖片

接下來我來利用ZScreen的Screenshots(圖片擷取)功能,來一氣呵成地擷取網頁圖片、直接上傳到ImageShack、取得圖片網址等一連串的動作。

開啟圖片擷取功能

image

ZScreen可以利用快速鍵、在通知列中的圖示按右鍵並進入「Quick Actions」、或是開啟Actions Toolbar來啟用擷取功能。擷取螢幕的功能有:

  • Entrie Screen:擷取全螢幕,預設快速鍵為PrintScreen鍵。
  • Selected Window:選擇部分視窗,預設快速鍵為Shift + PrintScreen,他會提示你選擇要擷取的範圍,可以是整個視窗、視窗中的一個元件的部份等,相當方便。
  • Crop Shot:擷取自訂範圍,預設快速鍵為Ctrl + PrintScreen,他會提示你選擇要擷取的範圍,畫面上會有尺規方便你度量。
  • Last Crop Shot:擷取上一次的擷取範圍,沒有預設快速鍵。
  • Auto Capture:詳細的擷取功能,可選擇延遲擷取的秒數,如下圖。沒有預設快速鍵。
    image
利用Selected Window選擇要擷取的範圍

image

利用「Selected Window」功能可以準確地選擇要擷取的網頁範圍,請用上述的方法來啟用「Selected Window」擷取功能吧。

上圖是正在使用Selected Window的擷取功能,你可以看到ZScreen會用紫色的尺規框線來提示你要選取的範圍。移動滑鼠的同時,他也會隨之改變選取範圍。他會很聰明地辨識視窗的元件與範圍,讓你快速抓到要擷取的網頁內容。確定要擷取的範圍之後,按下滑鼠左鍵即可完成擷取。

ZScreen自動上傳

image

擷取完成之後,通知列的ZScreen圖示會變成橘字,這表示ZScreen正在處理上傳圖片的動作,請稍待片刻。上傳完成之後,ZScreen就會顯示上傳完成的提示,如上圖。而上傳的圖片網址也自動地放到你的剪貼簿去了,你可以用貼上快速鍵「Ctrl + v」來將網址貼到你正在書寫文字的地方:

http://img63.imageshack.us/img63/2171/ss20101010235921o.png

在Histroy查詢已上傳的圖片

image

透過ZScreen上傳的資料會全部記錄在History功能中,你可以開啟ZScreen的視窗,並切換到「Histroy」頁籤,就可以輕易地取得之前上傳的各種資料。

ZScreen從剪貼簿中上傳圖片

雖然他的螢幕擷取功能很豐富,但我個人仍偏愛使用FastStone Capture來截圖、編輯,然後將圖片複製到「剪貼簿」,再請ZScreen「上傳剪貼簿資料」來進行貼圖。

利用各種編輯工具完成圖片,並且複製到剪貼簿

image

上圖是利用FastStone Capture編輯完成後再FastStone Editor編輯的畫面,當我確定我圖片可以上傳之後,只要按下「Ctrl + c」複製此圖片,就可以準備利用ZScreen進行上傳了。

ZScreen上傳剪貼簿資料

跟擷取螢幕的功能一樣,你可以從通知列的ZScreen圖示上按右鍵並進入「Quick Actions」、或是開啟Actions Toolbar來啟用Clipboard Upload(上傳剪貼簿資料)功能。

  • Clipboard Upload:上傳剪貼簿中的資料。預設快速鍵是Ctrl + F6

我個人習慣利用快速鍵Ctrl + F6來啟用上傳剪貼簿的功能。啟用此功能之後,跟擷取螢幕一樣地,通知列的ZScreen圖示會變成橘色字,再稍等一下就會顯示上傳完成的通知囉。

結語

我一直認為「工欲善其事,必先利其器」是一句至理名言。利用ZScreen來幫助我上傳圖片,我就可以一邊寫Plurk,一邊擷取並上傳自己要的圖片(或是備份原本已經在網路上的圖片),最後整合上傳圖片的網址與文字資料,寫出一則圖文並茂的訊息。日後我也能回去ImageShark來查看、整理之前上傳的圖片,而不必擔心當初寫在噗浪中的圖片在不知不覺中被人拿掉。

其實ZScreen還有很多功能可以使用,就等其他人繼續挖寶囉!

(more...)

論文進度報告(2010/10/10):幾乎完成工具列

布丁布丁吃布丁

論文進度報告(2010/10/10):幾乎完成工具列

image

上次的進度報告之後又隔了兩個多禮拜,最近也是一直在研究JavaScript的基礎技術,然後一邊在Blog把整理好的東西寫出來,希望能給一同鑽研JavaScript的程式設計師作為參考。評估各種寫作方式並訂定之後,就是繼續兩個禮拜之前停頓的進度,而繼續把工具列的部分完成。現在工具列只差「通知」功能尚未實作,但這是要等標註功能實作之後才會有通知,接著才是繼續完成這部份的功能。接下來就是要整理標註功能的UML了呢,又是一項大工程。在這之前,先來整理目前的論文進度吧。

目前的WebApp端的進度

元件 預估程式數量 已完成 UML類別圖
toolkit 17 17 1
core 15 13 1
kals_window 6 6 1
kals_toolbar 30 24 2
kals_text 38+? 0 3
search 6+? 0 1
統計 112+? 60 (53.5%) 9

整體來看,目前完成了大約一半的程式。由於使用物件導向架構開發,每個細節元件都是取用於toolkit或core中的上層元件,在開發同時也會不斷地改良這些元件,因此系統開發的速度會越寫越快。當然,這只是理論上而已。

也許會有人注意到類別程式的數量跟之前比起來有所減少,從之前的114降低到了112。我嘗試簡化系統的功能跟開發的方式來讓整個專案能更快完成,目前是將「自訂外觀」、「個人相片」的功能取消,暫緩適應小螢幕的功能調整(toolkit設計時有考慮小螢幕,但不一定每個功能都能適用就是);而開發中也只對關鍵功能設計單元測試,並且緊對Firefox進行測試,Chrome、IE、Android則在未來有機會時再進行統一的檢查。

navigation

上圖是kals_toolbar中navigation的UML類別圖,這是工具列上各個視窗的功能設定。其中灰字的類別則是暫停開發的類別。詳細的UML類別圖,請參考KALS Wiki

至於專案時程仍暫時維持在19天後完成,也就是10月29日。能不能完成我也沒把握,只能說盡力而為而已。

一改再改的JavaScript物件導向繼承寫作方式

一開始我的JavaScript是用最原始的prototype繼承法,但是由於這種方式在使用上會有些問題,而且我需要使用上層類別的方法,所以又花了一段時間回頭找尋相關資料學習。

首先學習到的是call跟apply的用法,但是發現到JavaScript仍有傳址問題存在,所以又把所有的屬性與方法寫在類別的建構子裡面,不過那將會造成系統資源大量消耗的問題,不得不再找尋新的方法。

接著找到的是Dean Edwards的Base繼承類別,他的確是很好用,寫法簡潔明瞭、又有呼叫上層類別方法的this.base()可使用,但是我使用的Aptana Studio看不懂,而我另外又試用了五六種JavaScript IDE,一樣是看不懂。儘管我後來找到讓Aptana Studio能夠理解的Base繼承法,但是最後仍毅然決然地使用最原始的prototype繼承法。

這是因為我在找尋這些方法的期間,學習到了prototype利用call、或是經典的base方法來呼叫上層或甚至是其他類別的方法來繼承並覆寫,讓prototype的寫法有了更多彈性,而能夠滿足系統的需求。儘管寫起來是比Base繼承法繁雜許多,但是由於prototype繼承法容易分析,許多JavaScript IDE都能理解,也是JavaScript程式設計師應該要知道的基本功課,這是我最後選用prototype繼承法來開發的原因。

這段期間不僅是一直翻閱相關資料、測試方法的優劣,還把系統的所有程式改寫了三次之多,著實非常地花時間,但也因此學到了不少東西。

重新檢視單元測試的必要性

core

在撰寫toolkit跟core的時候,我會要求自己盡量撰寫單元測試,並且最好是能夠測試到所以功能,也就是要求高「測試覆蓋率(Code coverage)」。上圖是core的UML類別圖,其中橘色的小註解標示著這部份的系統有設計單元測試的意思。小小的15個類別裡面,就有7個單元測試,力求核心元件要穩定。

過於繁雜的單元測試

上述在核心的工具時還可以做,到後面設計UI時,設計單元測試就越來越麻煩。我是用setTimeout來設計成機器人的方式,利用jQuery去選擇物件來點選元件或輸入資料,用以測試功能是否正常運作。但是這個機器人也常常做出一般人沒辦法做到的功能,導致測試的水準是比實際上更為高。舉例來說,原本使用者不可能點到某些隱藏起來的按鈕,可是用jQuery去點就可以點到、使用者必須等待視窗關閉並開啟之後才能執行下一個動作,可是jQuery就是無視視窗開閉來進行動作,導致他找不到下一個視窗的功能。也許是我設計單元測試的方法不對,但目前這樣做的確是很累,也顯得不切實際。

總結以上,簡單來說有兩個問題:

  1. 設計單元測試比設計元件本身還花時間,頗有本末倒置的情況發生。
  2. 單元測試不見得切合真實手動操作的情況。畢竟UI設計不像之前的計算用或存取用的程式這麼單純。

因此有必要重新檢討單元測試的必要性。

選擇重要的功能設計單元測試

仔細想一想,不需要全部功能都進行單元測試,去拼那個「測試覆蓋率」實在是很浪費時間與精力,只需要針對重要的功能設計單元測試即可。具體來說,針對具有以下兩種條件的功能來設計單元測試最為實用:

  1. 關鍵功能:千萬不能出錯的功能,當然要用單元測試確保他的正確性。
  2. 多道手續:與其說是在意其正確性,不如說是檢查時因為手續太多很麻煩,不如設計成單元測試的機器人讓他自己跑出的目標功能,再看看哪裡有問題,可以省下許多手動操作的時間。

也就是說,即使很重要的功能,但是如果很簡單就可以手動進行測試,或是其他測試中已經會使用到的功能,那麼就不需要刻意地撰寫單元測試。

程式要經過測試才算是完成。我仍然堅持這個最低底線,但現在並不強求一定要設計成自動的單元測試,即使是手動測試也可以算是勉強及格。

缺乏多人合作的遺憾

寫著寫著來講一個額外的小故事。

有天晚上回到宿舍的時候,發現室友學弟的位置旁坐著另一位學生。

學弟是資科所的學生,研究題目是跟雲端相關,當然也是寫程式的工作。看起來他應該是跟他同學兩個人正在趕一個系統,我偷偷地瞄到了phpMyAdmin的介面,兩台Mac筆電外加一個外接螢幕通通擺在桌上,旁邊還有喝到一半的五十嵐珍奶,看來晚上是要熬夜拼進度了。

老實說,我很少與人一起分工合作地寫程式。教人寫程式的經驗很多,但是可以像學弟他們那樣,「那個帳號登入的部份就拜託你了。」「OK!」地將一個系統分成幾個部分、再各自完成的經驗則是相當地少。不過架伺服器的各功能分工倒是有的,教育部計畫的時候,但那畢竟是功能調整,不太像是寫程式的這種「創作」。

我知道這種分工合作經驗的重要性對於程式開發來說並不亞於技術知識,大型的、有價值的系統是無法、也沒有時間讓我自己一個人完成,而我知道這正是我的弱點。至今我仍然是一個人在寫著程式,就像是現在正在做的碩士論文一樣。

儘管如此,我也在學著讓自己的程式「更好讀」、「更容易讓人使用」。像是建立嚴謹的物件導向架構程式讓人方便使用、遵守PHPDoc、JSDoc、cssdoc這種具有標準規範的註解讓人容易閱讀、利用UML跟網站草圖讓人理解整個系統,使用甘特圖與Wiki共筆工具來模擬多人合作時的專案互動。

我希望我能夠有資格與未來的夥伴一起合作開發一個大型的系統,所以我要加油,嗯。

結語

現在最令人擔心的是,19天後到底能不能完成系統呢?即使系統完成,後面還有好多後續的動作要做,多到讓人現在不想要面對的事情。能在這學期畢業嗎?能在明年3月之前如期把論文交給國中圖嗎?問題實在是太多了。現在還會有人問我要不要繼續念書,還是去當兵,還是要去當資訊替代役,但是現在能不能畢業都不知道啊XD

總之,每天都努力地繼續寫程式、寫Blog記錄,努力地向前進吧。

題外話,國慶日當天寫進度報告真是格外值得紀念?

(more...)

JavaScript物件導向繼承:以prototype方式繼承中需要呼叫constructor的問題

布丁布丁吃布丁

JavaScript物件導向繼承:以prototype方式繼承中需要呼叫constructor的問題

image

Dean Edwards認為更好的JavaScript物件導向應該有的其中一個條件是「I want to avoid calling a class’ constructor function during the prototyping phase」(在原形宣告期間,要避免去呼叫類別的建構子),這是由於JavaScript傳統的prototype繼承方式中,總是一直去呼叫父類別的建構子,才能讓子類別進行繼承。也就是說,父類別建構子裡面做過的事情,在該類別「真正派得上用場」之前,就得先做過一次,白白消耗客戶端的記憶體及運算時間。

這一篇是為了記錄究竟什麼是「原形宣告期間(prototyping phase)就呼叫建構子(constructor)」的問題,以及父類別的建構子裡面盡量不要使用太多動作的消極建議,最後簡單地介紹使用Dean Edwards的Base類別改善方法的優缺點。

JavaScript的prototype繼承方式

以下我舉一個簡單的JavaScript以prototype方式繼承的兩個類別「A」跟「B」,說明一併寫在註解裡面:

//建立類別A,以下是建構子(constructor)
function A() {
    //在畫面中輸出[Call A's constructor],表示執行A的建構子
    document.write("[Call A's constructor]");
}

//A的方法,稍後會給B繼承
A.prototype.method = function () {
    //表示執行A的方法
    document.write("[Hello, world!]");
};

//建立類別B,以下是建構子
function B() {
    //在畫面中輸出[Call B's constructor],表示執行B的建構子
    document.write("[Call B's constructor]");
}

//prototype方式的繼承。注意,此處呼叫了A類別的建構子
B.prototype = new A();    //畫面輸出[Call A's constructor]

//實體化類別B到變數b中
var b = new B();    //畫面輸出[Call B's constructor]

//呼叫由類別A繼承來的方法
b.method();    //畫面輸出[Hello, world!]

執行到最後,畫面上會輸出「[Call A's constructor][Call B's constructor][Hello, world!]」。然而理想上,程式的最後只有實體化類別B、沒有實體化類別A,因此應該只要呼叫到類別B的建構子,而不需要呼叫到類別A的建構子。但是實際上這種prototype繼承方式,卻是會在繼承時強制地呼叫類別A的建構子,造成資源的消耗。

設計建構子的心得

其實不僅僅是上述的問題,就連類別中的「物件類別(Object)」屬性也會受到JavaScript屬於傳址運作而可能遭受子類別影響的缺點(詳細請看我另一篇的討論),而必須在建構子中加入初始化屬性、並且呼叫父類別建構子。這即使在Dean Edwards繼承庫中,也會有一樣的問題。

換句話說,重複呼叫父類別建構子,似乎是難以避免的一個難關。在此前提之下,就是盡量不要在建構子中寫入太多程式、執行太多動作,最簡單的只要將物件類別的屬性初始化就好。

有些JavaScript程式設計師會在類別的建構子中宣告許多動作,但在建構子會被重複呼叫的前提下,這顯然地並不是很好的作法。舉例來說,以下就是在類別的建構子中宣告屬性與方法的JavaScript類別寫法,但是這會在每次呼叫建構子時重複地被執行、佔用記憶體,因此並不是很好的寫法。

function test() {
    var private1 = "I'm private variable 'private1'!";//私有成員變數
    this.public1 = "I'm public valiable 'public1'!";//公開成員變數
    function getPrivateFriend() {//私有成員函數
        alert(private1);
    }
    this.getPrivatePublic = function() {//公開成員函數
        getPrivateFriend();
    }
}

儘管如此,唯一令人欣慰的是,在繼承階層中最底層的子類別則就沒有上述的限制,因為他們不需要被別人所繼承,而他們通常也是系統中最常在建構子寫入大量動作的類別。

改用Dean Edwards的Base類別如何?

Dean Edwards針對這個問題提出了改良後的JavaScript物件導向繼承類別:Base (SkyDrive備份),這種方式可以避免呼叫到上層類別的建構子。

以下是上述範例中使用Dean Edwards的Base改良後的程式碼,請注意必須先引用Base.js喔。

<script type="text/javascript" src="Base.js"></script>
<script type="text/javascript">
//建立類別A,繼承自Base類別
A = Base.extend({
    //建構子
    constructor: function () {
        //在畫面中輸出[Call A's constructor],表示執行A的建構子
        document.write("[Call A's constructor]");    
    },
    method: function () {
        //表示執行A的方法
        document.write("[Hello, world!]");
    }
});

B = A.extend({
    //建構子
    constructor: function () {
        //在畫面中輸出[Call B's constructor],表示執行B的建構子
        document.write("[Call B's constructor]");
    }
});

//實體化類別B到變數b中
var b = new B();    //畫面輸出[Call B's constructor]

//呼叫由類別A繼承來的方法
b.method();    //畫面輸出[Hello, world!]
</script>

最後畫面上會輸出「[Call B's constructor][Hello, world!]」 ,由此可知他並不會呼叫到類別A的建構子,而且整體程式的排版更為直觀、易讀。

image

但是這種方法的缺點在於JavaScript IDE不支援,即使是我使用過最聰明的Aptana Studio也看不懂Dean Edwards繼承類別的運作方式,所以上圖的自動提示中是找不到類別B所繼承的方法method。

結語

其實一開始看到Dean Edwards提出這個問題時,我還看不懂這是什麼意思。直到實作了一段時間之後才發現原來建構子真的一直被重複呼叫,特別是我在系統中使用了多層次的類別繼承,導致呼叫次數多到一種難以想像的地步。

我試著用prototype的方式來挑戰嘗試迴避這個缺點,但是並沒有成功地找出解法。看來還是得用Dean Edwards的Base類別之類的迂迴手法才能解決這個問題吧?但是Base類別會讓Aptana看不懂,會影響到開發時候的效率,各有優劣,就看大家怎麼考量了。不過為了解決這個問題,我也想到一種「偽裝繼承」的方式來讓Base能夠用在Aptana Studio當中,下次有機會再來講講。

(more...)

NetBeans的JavaScript編輯中呼叫自動完成功能(Code Completing)

布丁布丁吃布丁

NetBeans的JavaScript編輯中呼叫自動完成功能(Code Completing)

image

NetBeans是用來撰寫網頁程式語言的整合開發環境(IDE)。他的特色之一就是程式碼的自動完成提示(Smart Code Completion),這也是我認為IDE應該要有的基本功能之一。然而NetBeans在撰寫JavaScript的時候,除非手動打開自動完成功能,不然只有在輸入觸發關鍵字「.」的時候才會顯示自動完成提示。也就是說,像我輸入常用的字詞,例如「var」、「new」、「function」等關鍵字的時候,他根本就不會出現提示,然後我就會很手殘地老是把「function」打成「funciton」,程式出錯跑不出來。

為了要在輸入一般文字時就能呼叫自動完成功能,我需要使用NetBeans的快捷鍵Ctrl+Space,然而他卻很不幸地跟Windows的切換輸入法相衝。因此又得修改快捷鍵設定,才能順利地呼叫NetBeans的自動完成功能。

以下介紹中,我使用的是NetBeans 6.9版本,作業系統是Windows 7 64-bit。但不管哪個版本,應該大致上都大同小異。

預設呼叫自動完成的快捷鍵 Ctrl + Space

image

要呼叫自動完成的快捷鍵(Hotkey),預設是使用「Ctrl + Space」。同樣身為中文Windows使用者的您看到這邊一定是滿臉陰影,因為Ctrl + Space是Windows用來切換輸入法的快捷鍵,在NetBeans中根本就沒辦法用Ctrl + Space來呼叫。

NetBeans的FAQ裡面也有提到這個問題,而他建議去設定Keymap來修改這個快捷建設定。接下來我們也照著他的方法來修改NetBeans呼叫自動完成的快捷鍵吧。

修改快捷鍵設定為 Alt + Z

基於Aptana StudioSpket IDE等我常用的IDE的習慣,通常呼叫自動完成的快捷鍵是設定在Alt + Z,這個按鍵也非常容易使用,因此以下我介紹如何將NetBeans的自動完成快捷鍵設定為Alt + Z。

  1. 開啟Tools中的Options。
    image 
  2. 切換到Keymap分頁,並在Search in Shortcuts欄位中輸入空白鍵,你就可以找到「Show Code Completion Popup」,而他後面的Shortcut(快捷鍵設定)則是「Ctrl+SPACE」
    image
  3. 雙擊要修改的快捷鍵設定,並按下「Alt」跟「Z」,並按下「Enter」確定。按下Enter之後列表會跳掉,但是再回去Searhc Alt+Z的時候,就會看到修改已經完成:
    image 
  4. 按「Ok」按鈕完成設定,然後在寫JavaScript的時候就開心地使用Alt + Z來呼叫自動完成吧。
    image


結語

在尚未得知這個方法之前,我一直以為NetBeans的自動完成非常地彆腳。我喜歡Aptana那種輸入第一個字就會立刻帶出自動完成的設定,而至今我還沒有在其他JavaScript IDE看到能在這點與他相比的特性。然而退而求其次,在這種按「Alt + Z」才能呼叫自動完成的IDE中雖然需要多一個這樣的步驟,但習慣了也勉強可以接受。

NetBeans的自動完成提示最貼心的地方在於會將重要的屬性與方法往上提,而不是像Aptana把所有的名稱都依照字母排序,只是幫你找出符合開頭的文字。

image

然而遺憾的是,NetBeans的JavaScript分析器不如Aptana來得聰明。而且他說是支援JSDoc,可是又不是很標準的JSDoc語法。像是JSDoc網站上認定的繼承語法「@extends」在Aptana跟Spket IDE都可以使用,到了NetBeans當中就只能認得「@inherits」。

因此到了最後,我還是繼續用Aptana來開發JavaScript。真有種繞了一大圈之後又回來原地的感覺。

(more...)

談JavaScript使用prototype實作物件導向的探討

布丁布丁吃布丁

談JavaScript使用prototype實作物件導向的探討

image

JavaScript雖然是物件導向的程式語言,但是他的物件導向方法並不統一,跟我們在學校所學的C、Java或甚至是PHP等都有很大的差異。

最知名的JavaScript繼承方法之一是使用「prototype」(此處並不是在講Prototype的JavaScript Framework喔),Fillano(馮旭平)談論物件導向Javascript - 實作繼承的效果為prototype的繼承方法作了很多說明,網路上也有很多教學是以「prototype」方式進行,例如JSDoc在介紹使用方法中就有示範一段以prototype作為繼承的例子。

我在論文系統發展初期也是使用prototype來實作繼承,但是做到一半的時候,我發現prototype其實是有很多問題的。除了老是要撰寫「this.prototype.」的宣告開頭讓程式大小居高不下,prototype還有使用「傳址」(連結位址) 而非「傳值」(複製資料) 來初始化變數的缺點,這會導致繼承時上層類別的變數會因為傳址而被變更的問題。

這一篇就是要來談談JavaScript中以prototype實作繼承的這個問題,並且一一探討解決的方法。


prototype實作繼承的方法與問題

prototype是JavaScript物件中特殊的一種屬性,透過指定prototype屬性,便可以指定要繼承的目標。然而當類別的屬性為「物件」的資料型態(例如有個屬性為birthday物件,而該物件包含了year、month、day這三種屬性),而方法本身又是修改該屬性中的屬性(例如修改birthday中的year這個屬性)時,就會影響到上層物件的屬性內容。

以下我舉一個簡單的範例:「Ancestor」上層類別跟「Child」子類別。首先下圖是他的UML類別圖:

image

將上面的類別圖寫成JavaScript物件導向的繼承,就會變成下列的程式碼:

//上層類別
function Ancestor() {
    this.setBirthdayYear(1889);
}

//屬性
Ancestor.prototype.birthday = {
    year: null,
    month: null,
    day: null
};

//方法
Ancestor.prototype.setBirthdayYear = function (year)
{
    this.birthday.year = year;
}; 

//子類別
function Child() {
    //即使Child沒有宣告setBirthdayYear的方法,
    //也可以使用上層類別Ancestor的setBirthdayYear
    this.setBirthdayYear(1915);  
}

//Child繼承Ancestor
Child.prototype = new Ancestor();   

最重要的繼承方法是最後一行「Child.prototype = new Ancestor();」,透過此宣告,Child類別就能使用上層類別Ancestor的屬性birthday跟方法setBirthdayYear()。

乍看之下這樣是沒有問題的,但是實際上Child在執行setBirthdayYear時,卻會連帶地影響到Ancestor的birthday屬性。舉例來說:

var ancestor = new Ancestor;
var child = new Child;
document.write(ancestor.birthday.year);    //應該要顯示1889,但卻顯示1915
document.write(child.birthday.year);    //顯示1915

很遺憾地,Ancestor的birthday屬性的確被Child修改了。由此可知,這種JavaScript物件導向的實作方式有著傳址運作的缺陷。

改進prototype的實作方式:在constructor指定參數

要改善上述實作方式的方法之一,是在constructor(建構子)的時候指定參數,讓每次類別在實體化成為物件的時候,都去重新指定參數的內容。以下是修改之後的Ancestor類別:

//上層類別
function Ancestor() {
    //初始化屬性
    this.birthday = {
        year: null,
        month: null,
        day: null
    };
    
    this.setBirthdayYear(1889);
}

在建構子當中加入屬性初始化的設定之後,就算之後Child修改了Ancestor的屬性,因為Ancestor在實體化的時候每次都會將屬性初始化,所以Ancestor看起來就像是不會受到Child影響一樣。

值得注意的是,這只有在屬性為物件時才可能會受到影響,請對可能受到影響的屬性物件進行初始化,如果屬性的資料型態為字串、數字、布林值,那麼即使不進行初始化也是無所謂的。相關的探討請見JavaScript中參數的傳值與傳址探討

這樣做是正確的,但在多重繼承的時候,仍會有一些問題發生。請繼續看以下的探討。

多層繼承時將會導致問題發生

儘管上一節中為類別的建構子加入初始化屬性的設定,就可以暫時解決上層類別受到影響的問題,但是如果要實作多層繼承的時候,卻仍因為最下層類別不會去執行最上層類別的建構子,導致最後仍沒有進行初始化屬性的錯誤。

接下來我再舉一個例子作為說明,以下是多層繼承的UML類別圖:(雖然這並不是一個很標準的物件導向的例子,大家請不要見怪。)

image

現在我們有4個類別,各別是Grandfather爺爺、Father爸爸、Son兒子、Daughter女兒。他們用上述的prototype實作方式來寫成JavaScript程式碼之後,會如以下:

//最上層類別
function Grandfather() {
    this.birthday = {
        year: null,
        month: null,
        day: null
    };
    this.setBirthdayYear(1889);
}

//屬性
Grandfather.prototype.birthday = {
    year: null,
    month: null,
    day: null
};

//方法
Grandfather.prototype.setBirthdayYear = function (year)
{
    this.birthday.year = year;
}; 

//上層類別
function Father() {
    this.setBirthdayYear(1915);    
}

//Father繼承Grandfather
Father.prototype = new Grandfather();    

//子類別之一
function Son() {
    this.setBirthdayYear(1943);    
}

//Son繼承Father
Son.prototype = new Father();    

//子類別之二
function Daughter() {
    this.setBirthdayYear(1945);    
}

//Daughter繼承Father
Daughter.prototype = new Father();

類別名稱修改,並且加入了Son跟Daughter這兩個類別之外,基本上跟前面舉例中的Ancestor與Child沒有太大差別。但是這樣子執行的時候,卻會發生很大的問題:

var grandfather = new Grandfather();
var father = new Father();
var son = new Son();
var daughter = new Daughter();

document.write(grandfather.birthday.year);    //顯示1889
document.write(father.birthday.year);    //應該要顯示1915,但卻顯示1945
document.write(son.birthday.year);    //應該要顯示1943,但卻顯示1945
document.write(daughter.birthday.year);    //顯示1945

你可以注意到,Daughter修改了屬性的資料,連帶影響到了Father跟Son,也就是說,除了最上層Grandfather因為有在建構子時初始化屬性之外,其他沒有在建構子中初始化屬性的子類別仍會受到影響。

你可能想到說:那麼同樣地也在Father、Son、Daughter時初始化屬性不就得了?但這樣的作法是與物件導向中為了不要重複撰寫程式碼的原則相違背,因此並不推薦這麼做。

解決方式:在建構子呼叫上層類別的建構子

為了解決上述的問題,就必須在建構子呼叫上層類別的建構子,確保子類別每次實體話的時候也能夠初始化屬性。

在上述例子中,只要修改Father類別,讓他在建構子當中初始化就可以了。讓我們用JavaScript中經典的prototype base繼承法來取得並執行上層物件的建構子,修改之後的Father類別如下:

//上層類別
function Father() {
    this.base = Grandfather;
    this.base();
    this.setBirthdayYear(1915);    
}

加入了中間那兩行便可以呼叫上層類別的建構子,透過這種指定方式,this.base會被當做是Grandfather這個function(也就是Grandfather的建構子),然後在下面呼叫this.base()的時候,就會把Grandfather做過的事情再做一次,也就可以達到呼叫上層建構子的這個目的了。

除了這個方法之外,也可以使用call()函式來取得上層建構子。以call()來修改的Father類別如下:

//上層類別
function Father() {
    Grandfather.call(this);
    this.setBirthdayYear(1915);    
}

call()會將Grandfather裡面的this以輸入的參數取代並執行一遍,而現在輸入的參數是Father的this,因此就等於Father中去執行Grandfather的建構子一樣的意思。call()方法可以說是比base更為簡潔且直覺的實作方法,詳細的內容可以參考ECMA-262的13.2.1 [[Call]]方法的定義

最後讓我們重新看一下以call()修改之後的四個類別多層繼承的程式碼:

//最上層類別
function Grandfather() {
    this.birthday = {
        year: null,
        month: null,
        day: null
    };
    this.setBirthdayYear(1889);
}

//屬性
Grandfather.prototype.birthday = {
    year: null,
    month: null,
    day: null
};

//方法
Grandfather.prototype.setBirthdayYear = function (year)
{
    this.birthday.year = year;
}; 

//上層類別
function Father() {
    Grandfather.call(this);
    this.setBirthdayYear(1915);    
}

//Father繼承Grandfather
Father.prototype = new Grandfather();    

//子類別之一
function Son() {
    Father.call(this);
    this.setBirthdayYear(1943);    
}

//Son繼承Father
Son.prototype = new Father();    

//子類別之二
function Daughter() {
    Father.call(this);
    this.setBirthdayYear(1945);    
}

//Daughter繼承Father
Daughter.prototype = new Father();

//輸出檢驗
var grandfather = new Grandfather();
var father = new Father();
var son = new Son();
var daughter = new Daughter();

document.write(grandfather.birthday.year);    //顯示1889
document.write(father.birthday.year);    //顯示1915
document.write(son.birthday.year);    //顯示1943
document.write(daughter.birthday.year);    //顯示1945

結語

由於JavaScript是傳址的方式運作,所以在物件導向上會發生很多出乎意料之外的問題,讓我在這兩個禮拜一直在找解決的方法。這一篇寫了又改、改了又寫,反反覆覆地好多次,總算是把JavaScript用prototype的繼承方法有個比較完整的整理。網路上的資料零零散散地看了很多,大致上把比較有印象的列在下方供大家參考。寫這篇也是對自己這些日子學習JavaScript的繼承方法有一個交代,作為學習的一個筆記。

原本我用prototype的方式來寫JavaScript的繼承,但因為發現了這個問題,於是又想改用Dean Edwards的Base工具來實作繼承,但是這卻導致Aptana這個JavaScript IDE看不懂,讓IDE整個武功盡失。在找尋更為理想的解決方式時,又回來整理這一篇。

image

到目前為止,我發現Aptana IDE可以完全理解這種prototype繼承方法,甚至不需要用JSDoc的@extends標註繼承的對象,Aptana也可以理解並帶出上層類別的方法或屬性。

接下來我想要繼續研究一個可以支援我需要的物件導向功能,並且又能讓Aptana這種JavaScript IDE讀取分析的理想實作方式。待我程式實作到一定程度時,確認都沒有問題了,我再把我的方法整理之後寫上來吧。


參考資源

(more...)

JavaScript中參數的傳值與傳址心得

布丁布丁吃布丁

JavaScript中參數的傳值與傳址心得

image
JavaScript中參數傳遞到底是「傳值」(passing by value) 還是「傳址」(passing by refernce) ,似乎常常造成許多人混亂。我自己原本也一直以為JavaScript只是傳值而非傳址,而為此混亂了好一陣子。特別是在撰寫物件導向的JavaScript程式時更容易造成混亂。
有人認為JavaScript的函數(function)會依據你輸入參數的資料類型來區分傳值還是傳址,物件(object)的話會使用傳址,非物件的則是使用傳值。但實際上,我認為JavaScript的本質是傳址而非傳值。而端看你在函數裡面是否修改參數的記憶體位址(也就是建立新的資料給參數),來決定是否影響函數之外的參數資料。
以下我們就來一一地檢視一下JavaScript究竟是傳值或是傳址的參數傳遞運作方式吧。

2016/1/14更新:根據底下留言網友討論指出了我原文的錯誤,可以發現其實JavaScript本質仍是「傳值而非傳址」。雖然下面文章仍放著給大家參考,但下面的討論更有看頭。希望觀看這篇的讀者能夠連下面的討論一併閱讀,方能深入瞭解JavaScript的奧妙。

參數傳值:Number、String、Boolean等非Object類型

當輸入給函數的參數類型為非物件(object)的資料型態,例如Number(數字)、String(字串)或是Boolean(布林邏輯值)的時候,JavaScript的函數會以傳值的方式來處理。傳值的意思是說,輸入到函數裡面的參數會被複製一份,而在函數裡面對參數的操作,不會影響到外在參數的影響。
以下是一段示範用的程式碼:
<script type="text/javascript">
//宣告變數,資料類型為字串
var paramA = 'original';

//確認變數資料
document.write(paramA + '<br />');    //輸出 original

//定義函數,在函數中修改參數資料,並且輸出做確認
function changeParamA(paramA)
{
    //修改參數
    paramA = 'changed';
    
    //確認被修改之後的參數資料
    document.write(paramA + '<br />');    //輸出 changed
}

//在函數中修改參數
changeParamA(paramA);    //在函數中運作,輸出 changed

//被函數修改之後,仍然維持原本的資料
document.write(paramA + '<br />');    //輸出 original
</script>

上面的例子的輸出結果將會是:
original
changed
original

由此可知,JavaScript函數中使用參數為字串資料類型時,將會是以傳值的方式運作。同樣的道理也適用於數字、布林值上。

參數傳址:Object

當輸入給函數的參數資料類型為Object(物件)時,JavaScript會以傳址的方式來處理。傳址的意思是說,輸入的函數裡面的參數只是「記憶體中的位置」,而在函數裡面對參數的操作,其實是對記憶體位置中的該物件進行修改,因此函數之外的參數也會受到影響。
以下是一段示範用的程式碼:
<script type="text/javascript">
//宣告變數,資料類型為物件
var paramB = {
    attr: 'original'
};

//確認變數資料
document.write(paramB.attr + '<br />');    //輸出 original

//定義函數,在函數中修改參數資料,並且輸出做確認
function changeParamB(paramB)
{
    //修改參數。注意修改的方式,是直接指定物件的屬性進行修改,而非建立新的物件。    
paramB.attr = "changed";
    
    //確認被修改之後的參數資料
    document.write(paramB.attr + '<br />');    //輸出 changed
}

//在函數中修改參數
changeParamB(paramB);    //在函數中運作,輸出 changed

//被函數修改之後,物件的屬性也跟著改變了
document.write(paramB.attr + '<br />');    //輸出 changed
</script>

上面例子中輸出的結果將會是:
original
changed
changed

在上面的例子中,你可以發現到以物件資料型態輸入函數中的參數,在函數中被修改之後,在函數之外也會跟著受到影響,一般來說這會被視為傳址的參數傳遞方式。

再探Object的參數傳遞

在上一節介紹傳址的例子中,函數修改參數的方式是指定物件的屬性進行修改。但是如果函數修改參數的方式是直接指定新的物件、或是輸入其他的資料類型,那麼函數之外的參數就不會受到修改,也就是傳值的參數傳遞。
以下是一段示範用的程式碼:
<script type="text/javascript">
//宣告變數,資料類型為物件
var paramC = {
    attr: 'original'
};

//確認變數資料
document.write(paramC.attr + '<br />');    //輸出 original

//定義函數,在函數中修改參數資料,並且輸出做確認
function changeParamC(paramC)
{
    //修改參數。注意修改的方式,是建立新的物件,而新的物件裡面也包含attr屬性。
    paramC = {
        attr: 'changed'
    };
    
    //確認被修改之後的參數資料
    document.write(paramC.attr + '<br />');    //輸出 changed
}

//在函數中修改參數
changeParamC(paramC);    //在函數中運作,輸出 changed

//被函數修改之後,仍然維持原本的資料
document.write(paramC.attr + '<br />');    //輸出 original
</script>

上面例子中輸出的結果將會是:
original
changed
original

你會發現到,即使輸入參數的資料類型為物件,但是當你在函數中為參數指定新的資料的時候,函數之外的參數並不會受到影響,是為傳值參數傳遞的運作方式。

推測JavaScript是傳址方式運作

因此由以上的例子中,我可以得到一個推測的結論:JavaScript一直都是用傳址的參數傳遞。只是根據函數對於參數是否變更參數的記憶體位址,而會有看起來像是傳值或傳址的運作差異。
在以物件傳遞、修改物件屬性的paramB例子中,函數本身並沒有修改參數的記憶體位址,也就是沒有給予paramB新建立的資料(新的資料就是一個新的記憶體位址),因此在函數中被修改的paramB,函數之外也會受到影響。
而paramA跟paramC的例子裡都是建立了新的資料給參數,修改了參數本身的記憶體位址,讓函數裡面運作的參數跟函數之外兩者互不相干,因此乍看之下就類似傳值的運作方式。

參數傳值或是傳址運作:Array

那麼我們再回頭來看看JavaScript中一種特殊的資料型態:Array(陣列)。陣列本質上屬於「Object」,那麼把陣列作為參數輸入函數時,究竟是傳值還是傳址呢?由前面的推論中可知,這是根據函數裡面對於參數的操作是否參數為建立新的資料來判斷
以下是一段示範用的程式碼:
<script type="text/javascript">
//宣告變數,資料類型為陣列
var paramAry = ['original'];

//確認變數資料
document.write(paramAry[0] + '<br />');    //輸出 original

//定義函數,在函數中修改參數資料,並且輸出做確認
function changeParamAry1(paramAry)
{
    //修改參數。注意修改的方式,是建立新的陣列。
    paramAry = ['changed'];
    
    //確認被修改之後的參數資料
    document.write(paramAry[0] + '<br />');    //輸出 changed
}

function changeParamAry2(paramAry)
{
    //修改參數。注意修改的方式,是修改陣列裡面的索引,而非建立新的陣列。
    paramAry[0] = 'changed';
    
    //確認被修改之後的參數資料
    document.write(paramAry[0] + '<br />');    //輸出 changed
}

//在函數中修改參數
changeParamAry1(paramAry);    //在函數中運作,輸出 changed

//被函數修改之後,仍然維持原本的資料
document.write(paramAry[0] + '<br />');    //輸出 original

//在函數中修改參數
changeParamAry2(paramAry);    //在函數中運作,輸出 changed

//被函數修改之後,參數的資料已經被修改
document.write(paramAry[0] + '<br />');    //輸出 changed
</script>

上面例子中輸出的結果將會是:
original
changed
original
changed
changed

因此你可以發現到,根據函數對於參數的操作,就會造成傳值或傳址的運作差異。

結語

當JavaScript越寫越複雜之後,對於參數的傳值或傳址就會越來越注重。也許是我讀的JavaScript的書不夠多,像這種基礎的概念居然都不是從書上得來,而是在網路上找尋各個程式設計師的心得與探討之後,再整理出來的。
題外話,因為這篇主要是整理理論的東西,沒什麼圖片。秉持著一篇文章一定要有一張圖的精神,就去ICON FINDER找了張JavaScript的圖示來貼在開頭XD 而最近都在談JavaScript的東西,因此我也為這個Blog加入了JavaScript的分類標籤。之前的發文就待有空時再來整理歸類到JavaScript標籤去吧。

參考資源

(more...)

Spket IDE使用jQuery自動提示

Spket IDE使用jQuery自動提示

image

Spket IDE是網路上知名的JavaScriptXML編輯器,有許採用jQueryExtJS工具庫的開發者都很喜歡使用Spket,而我在找尋理想的JavaScript IDE的時候,也來安裝Spket IDE來使用看看。

自動提示(Code Assist)是IDE中很重要的功能之一,效果就如上圖一樣,讓程式設計師在撰寫程式的時候,自動帶出相關的字詞,不僅減少程式設計師打字的工作量,也能夠避免輸入錯誤語法的人為失誤。然而似乎不少Spket IDE的使用者不清楚如何使用jQuery或ExtJS的自動提示功能,不僅Skpet IDE官方網站上有文字影片(簡體字?)的說明之外,Google中搜尋Spket IDE的介紹中也幾乎都是在教怎麼配置Profile

然而我照著教學上面的方法來做,卻始終帶不出jQuery的自動提示。找尋許多資料之後,終於在Spket IDE的論壇中發現了解決方法,因此想說在此整理一下,給有需要的朋友們一個引路。

環境敘述

image

Spket IDE可以作為plugin安裝在eclipse系列 3.2.x的IDE當中,而我是使用Aptana Studio 2,這是使用eclipse 3.5.2為基礎的IDE,也一樣可以安裝Spket IDE。而作業系統是Windows 7 64位元。

用網站安裝無效

image

原本我是使用eclipse的Install Software,連到Spket IDE的網站 http://www.spket.com/update 去下載1.6.18版本來安裝,但是這個版本似乎有問題,所以安裝之後仍然無法順利使用。

手動下載Plugin並安裝

根據論壇的說法,我將我的Skpet IDE安裝以及jQuery Profile配置的方法整理如下:

  1. 先安裝eclipse系列的IDE編輯器,例如Aptana Studio 2
  2. 下載com.spket.js_1.6.18.jar (SkyDrive備份)。
  3. 將com.spket.js_1.6.18.jar放置到eclipse安裝目錄底下的「plugins」資料夾。以Aptana Studio 2來說,就是「D:\Program Files\Aptana Studio\plugins\com.spket.js_1.6.18.jar」(因為我把Aptana安裝到D磁碟分割去了)
  4. 開啟eclipse,沒有錯誤訊息的話,應該就是安裝完成了。

接著是配置jQuery Profile:

  1. 打開「Window > Preferences」:
    image
  2. 左邊導覽列中,找到「Spket > JavaScript Profiles」,然後點選右上角的「New」以建立新的Profile:
    image
  3. 輸入Profile名稱,你看得懂就好,那就設定為「jQuery」吧。
    image
  4. 現在Profiles裡面多了一個剛剛建立的jQuery Profile,選擇他並點選右邊的「Add Library」:
    image
  5. 在選擇Library的下拉式選單中,選擇「jQuery」,然後按下ok完成:
    image
  6. 接著要加入jQuery的檔案,請點下右方的「Add File」:
    image
  7. jQuery的檔案最好是附加上說明的詳細版本,而不是一般使用的min版本,這樣在自動提示的時候才會把方法的說明也一併帶出來。在此推薦使用阿良翻譯的jQuery 1.3.2文件 (SkyDrive備份),請解壓縮之後選擇裡面的「jquery-1.3.2-jsdoc-Spket-profile.js」即可。
    image
  8. 完成後,選擇左方jQuery的Profile,並按下右邊的「Default」,讓Spket IDE把這個Profile作為預設的環境。
    image

儘管他們的版本號都是1.6.18,可是論壇上面的jar似乎比較正確。安裝正確的版本之後,不僅可以顯示jQuery的自動完成提示,也可以開啟Profile Explorer來查詢可用JavaScript語法。如下圖:

image


結語

儘管總算讓Spket IDE可以讀取jQuery的自動提示了,但是對於自己寫的程式,Spket IDE依然是不會弄出自動提示。接著我要繼續研究怎麼讓我寫的程式加入Spket IDE的自動提示中,如果這點可以做到的話,那麼Spket IDE就幾乎稱得上是理想的JavaScript IDE了。

(more...)

eclipse開啟時發生無法載入「jvm.dll」問題的解決方法

布丁布丁吃布丁

eclipse開啟時發生無法載入「jvm.dll」問題的解決方法

image

eclipse是知名的自由(也可以免費取用)的跨平台整合開發環境(Integreated Development Environment,簡稱IDE),主要用來開發Java,但他擁有強大的自訂能力,而使得eclipse也可以用來開發C/C++PHP或甚至是JavaScript。而許多IDE也是基於eclipse再擴充、發展而成,像是我目前主要用來開發JavaScript的Aptana Studio 2

問題敘述

eclipse能夠跨平台是基於Java運作環境的功勞,而他本身也是一個免安裝的檔案,理論上在良好設定的前提下,下載之後、解壓縮並直接開啟就能夠啟動。

最近為了再次找尋更完善的JavaScript IDE,所以我下載了Eclipse IDE for JavaScript Web Developers來使用。但沒想到下載完、解壓縮並開啟之後,出現了「Failed to load the JNI shared libray “D:\Program Files\Java\jre6\bin\client\jvm.dll”」的錯誤訊息,讓eclipse無法順利啟動。

這個問題顯然是我的Java環境參數哪裡弄錯了。我的電腦是Windows 7 64位元,安裝了Java的JDK 6.0.21,除了安裝路徑移至D磁碟分割之外,其他都跟預設一樣。

修改eclipse.ini,失敗

image

網路上可以找到兩種解決方法,一個是修改位於eclipse目錄底下的「eclipse.ini」設定檔。這個作法在「eclipse打开出现JVM terminated.Exit Code=-1错误的解决办法」這篇的後半部有提到,但我試著做卻很遺憾地沒能解決這個問題,而是需要用另一種方法來解決。

開啟eclipse時指定Java機器,成功

image

另一個方法是在開啟eclipse的時候,同時指定正確的Java虛擬機器路徑作為參數。作法如下:

  1. 找到你Java虛擬機器的路徑。以我的電腦為例子,因為Java安裝到D:\Program Files\裡面去了,所以路徑為「D:\Program Files\Java\jdk1.6.0_21\bin\javaw.exe
  2. 為「eclipse.exe」建立捷徑「eclipse.exe - 捷徑」,名稱可以隨意修改。
  3. 在捷徑上按右鍵,進入「內容」。
  4. 在「捷徑」分頁中找到「目標」欄位。
    image
  5. 在目標欄位資料後面加上「-vm "D:\Program Files\Java\jdk1.6.0_21\bin\javaw.exe"」,參數即是第一步中查詢的Java虛擬機器的路徑。舉例來說,原本的資料為「"D:\Program Files\eclipse\eclipse.exe"」,現在改為「"D:\Program Files\eclipse\eclipse.exe" -vm "D:\Program Files\Java\jdk1.6.0_21\bin\javaw.exe"」。
  6. 點擊捷徑,開啟eclipse。

image

開始使用eclipse吧!


結語

這其實是我第三次還是第四次遇到同樣的問題,而我卻每次都還是上網去找解決方法,找得灰頭土臉的才得到每次都一樣的解決方法。所以在此特地把這個方法寫在Blog,希望自己下次不要再這麼辛苦了。

題外話,Eclipse IDE for JavaScript Web Developers的JavaScript Editor在Aptana當中已有內建,而且也沒有Aptana JS Editor好用,著實讓人失望。下次有機會我在來分析一下JavaScript IDE的優缺點吧。

(more...)

論文進度報告(2010/9/26):進度延後至10/29

布丁布丁吃布丁

論文進度報告(2010/9/26):進度延後至10/29

image

9月中meeting時,我跟老師報告了一下系統狀況與現在的進度。當然就如你所知的,系統開發並不是很順利。前端的JavaScript程式完成了估計數量的1/3不到而已,之前說想要在9/21完成的希望,當然也是只能摸摸鼻子地再來重新估算日期。

系統現況與進度報告投影片

這是9/15論文進度報告的投影片(SkyDrive下載)。

前端的View部分,系統目前可以分成六大區塊:Toolkit工具箱、Core核心元件、Window視窗元件、Toolbar工具列、Text標註、Search搜尋。而目前我正在做到Toolbar這一塊,比報告之後又多推了一些進度,但跟上次報告時比起來也不過是多作了7隻程式而已,中間相隔約2個禮拜。

以下是進度的詳細內容:

元件 預估程式數量 已完成 UML類別圖
Toolkit 15 15 1
Core 15 13 1
Window 4 4 1
Toolbar 36 3 2
Text 38+? 0 3
Search 6+? 0 1
統計 114+? 35 (30.7%) 9

專案進度延後,設定10/29作為查核點

image

系統延後的狀況實在是太嚴重,嚴重到我都快對不起KALS Wiki左上角的倒數計時器。但是正視自己的弱點才能夠前進,所以還是要忍辱地再次調整專案規劃。

如果以兩個禮拜可以增加7隻程式來計算,大概還需要5個月的時間……當然不可能會到這麼久。而且這兩個禮拜中,又是寫書校稿、又是假期回家,所以進度才比慢到這麼誇張。不過都已經9月底的現在,說什麼理由也沒啥意義了。

總之,接下來兩個禮拜應該可以專心在系統上,因此要用這兩個禮拜來預估系統進度,然後設定10/29(五)作為查核點,再給自己一個月,看看情況如何吧。

image

由於整個進度都往後順延,影響到最後畢業的時程,延遲至3月初。由於我仍欠國中圖一篇論文,所以千萬得在3/24之前完成口試才行。

寫書一校完畢

image

之前提到的寫書工作,終於完成一校的作業了。

一校作業是由我跟老師分擔負責,我主要是檢查技術部分是否有問題。而不出所料地,我又作了很多修改。讓人有種「校稿怎麼校都校不完」的感覺。後來編輯又來告知說我圖檔dpi不足300,印刷時會讓圖片花掉,讓我又花了好多時間再來重新截圖。儘管現在都做完了,但二校時可能也會再來一次這種大混亂吧。

雖然老師希望該書在9月底能夠出版,但看現在的情況,能在10月底之前出版也許就該偷笑了?

與外國作者討論程式的感想

image

我在撰寫論文程式時,使用了Max Wheeler的PlaceHeld的外掛,並改進了裡面的一些小bug。這次心血來潮,上github將我的建議寫給作者Max,而他也在數天之後回了我。但他並不知道這樣改的意義,所以我又寫了一些範例回給他,現在在等他的回應。

以往我改了很多人寫的程式(特別是DSpace),有不少會在這個Blogger中寫出我改過的地方,但卻很少跟原作者交流、互動。我想,如果要成長的話,就一定要積極地與人交流知識才行。光是閉門造車,是很難有所成就的。

嗯,加油!


以往我總是將許多主題混在論文進度報告裡面一起寫,讓閒聊的事情與可能比較有教學價值的文章內容混淆。現在我打算把一些具有獨立探討價值的議題從論文進度報告中拆開來,進度報告歸進度報告(還有很多閒聊)、其他議題歸其他議題。也許這樣會對想要一次看完的讀者來說比較辛苦,但我相信將議題獨立探討,應該是更方便讀者找尋資料。

也因此,最近我發了很多篇文章,而談論議題都比較獨立。事實上,也還有好幾篇想寫議題列在待辦事項中,等待我一篇一篇地將他們完成。

(more...)