2009-12-11
tcllib 1.12 is out
官方網站還沒有更新,但是 SourceForge 檔案列表上已經有放上去檔案了。
Read Me 上的 Overview:
72 new packages in 10 modules
46 changed packages in 25 modules
14 internally changed packages in 12 modules
166 unchanged packages in 65 modules
301 packages, total in 95 modules, total
有趣的是,我看到有一個 coroutine package 包含在 1.12 這次的 release 裡,這需要 Tcl/Tk 8.6 或者是更高的版本才可以使用。
2009-10-25
更新 Windows 平台環境: 使用 ActiveTcl 8.6 beta-2
我發現 Active Tcl 更新了安裝檔案,所以也跟著更新了。這次的更新也更新了原本附帶的套件到目前的最新版(例如說 VFS),所以我已經昇級到這個版本了。
注意:這一版的 code base 仍然是 Tcl/Tk 8.6 beta 1,可以算是針對一些套件做 upgrade 的吧。
2009-10-23
清除掉 Visual C++ 2008 Express 最近使用的專案列表
package require registry
label .show -text "Below is the list:"
grid .show -row 0 -column 0 -columnspan 2 -pady 3 -ipady 1
set count 0
set rootKey "HKEY_CURRENT_USER\\Software\\Microsoft\\VCExpress\\9.0\\ProjectMRUList"
foreach id [registry values $rootKey] {
if {[string length $id] >= 4} {
set text [registry get $rootKey $id]
ttk::checkbutton .$count -text $text -variable check($id)
grid .$count -column 0 -columnspan 4 -ipady 1 -sticky nsew
set check($id) 0
incr count 1
}
}
proc doClean {} {
foreach id [registry values $::rootKey] {
if {[string length $id] >= 4} {
if {$::check($id) == 1} {
registry delete $::rootKey $id
}
}
}
exit
}
# Let our button in next row
incr count 1
button .exit -text "Exit" -command exit
grid .exit -column 2 -row $count -pady 3 -ipady 1 -sticky nsew
button .clean -text "Clean" -command doClean
grid .clean -column 3 -row $count -pady 3 -ipady 1 -sticky nsew
使用 checkbutton 建立列表,讓使用者選擇要清除最近使用的專案列表中的哪一個。我們使用一個陣列記住目前使用者的選擇,如果使用者按 Clean,就去清掉使用者所選擇的那些項目。Geometry Manager 使用 grid 來管理。
2009-10-10
tDom and TclXML
Tcl 是個極容易擴充的語言(並且因此影響到後面出現或者是同期的 scripting language),在處理 XML 方面,有二個主要的套件:
我會比較偏好 tDom,因為他雖然是用 C 實作,而且在架構上沒有 TclXML 的野心那麼大,但是 tDom 在管理上比較簡單(只有一個套件),不像 TclXML/TclDOM 需要好幾個套件組合起來、而且 TclDOM 隨著各個實作的不同,能力也不同(pure Tcl, Expat, libxml2)。
更多資料:TclDOM vs tDOM
TDBC 1.0 b13 已經包含 tdbc::postgres
package require tdbc::postgres
tdbc::postgres::connection create db -user danilo -password test -port 5432
set statement [db prepare {
SELECT VERSION()
}]
$statement foreach row {
puts [dict get $row version]
}
$statement close
db close
沒錯,確實已經可以運作了,而 tdbc::postgres 主要是透過 libpg 來實作的。另外,TDBC 同時也包含了 Oracle 的 driver,但是這一個我就沒有測試了。
2009-09-22
刪除 Adobe Flash Sol 記錄
set SolFile [set env(USERPROFILE)]
append SolFile {\Application Data\Macromedia}
if {[file exist $SolFile]==1} {
file delete -force $SolFile
}
使用了大絕招(加上參數 -force)來刪除目錄以及其中的所有檔案,這樣就可以半自動的刪除掉這些試圖記錄的資訊。如果有其它的需要或者是需要再增加其它的目錄進行刪除,只要修改一下就 OK 了。
2009-09-20
Eagle
Eagle (Extensible Adaptable Generalized Logic Engine) is an implementation of the Tcl scripting language for the Common Language Runtime (CLR).
這是個仍然在發展中的案子,把 Tcl 搬到 .NET 的世界了。
2009-09-15
Tcl and the Tk Toolkit Second Edition is out
雖然沒有加入 8.6 的 OO (物件導向)或者是其它的改進有點可惜,但是按照目前 8.6 的發展情況來看,加入的結果將會使這本書的出版更為難產,我想將版本放在 8.5 是個合理的決定。
目前和 Amazon 的書評綜合看起來,都是比較正面的評價,所以我想第二版仍然維持了清楚並且組織良好的風格,it is a good news.
Update:
2009/10/20 天瓏已經開始賣了,我已經拿到書了。
2009-09-13
2009-09-09
Tcl and the Tk Toolkit (2nd Edition)
ISBN-13: 978-0321336330
2009-09-05
Download and Uncompress zip file
在使用的過程裡,我發覺 vfs 1.4.0 應該是有 bug 的,如果要使用 vfs::zip 來解壓縮,要把版本昇到 1.4.1 才行。
下面是從臺灣證券交易所下載檔案,然後使用 vfs::zip 解壓縮的範例:
#!c:/tcl/bin/tclsh86.exe
package require http
package require vfs::zip
########################################################################
# Now download file from network
########################################################################
set day [clock format [clock seconds] -format {%d}]
set now [clock seconds]
if {$day > 7} {
set value [clock format [clock add $now -30 day] -format {%Y%m}]
} else {
set value [clock format [clock add $now -60 day] -format {%Y%m}]
}
set remoteFile "http://www.twse.com.tw/ch/statistics/download/04/001/"
append remoteFile $value
append remoteFile "_C04001.zip"
puts "======================================================"
puts "URL: $remoteFile"
set localFile $value
append localFile "_C04001.zip"
puts "Download File name: $localFile"
puts "======================================================"
set token [::http::geturl $remoteFile -binary 1]
set data [::http::data $token]
set channel [open $localFile w+]
fconfigure $channel -encoding binary -translation binary
puts -nonewline $channel $data
close $channel
::http::cleanup $token
########################################################################
# Now handle zip file
########################################################################
set mnt_file [vfs::zip::Mount $localFile $localFile]
file copy -force [glob $localFile/*] ./
vfs::zip::Unmount $mnt_file $localFile
file delete $localFile
幫朋友寫的,這樣再做一些適當的設定就可以定時下載最近的企業月報,而季報也可以比照辦理。
2009-08-02
在命令列呼叫 OpenOffice.Org Basic 巨集
OpenOffice.Org Basic 寫的程式:
REM ***** BASIC *****
Option Explicit
Sub AutoFindGoodMan(cFile)
Dim Doc As Object
Dim Dummy()
Dim Sheet As Object
Dim Cell As Object
Dim Cell2 As Object
Dim Cell3 As Object
Dim Cell4 As Object
Dim Count As Integer
Doc = StarDesktop.loadComponentFromURL(ConvertToUrl(cFile), "_default", 0, Dummy())
Sheet = Doc.Sheets(0)
dim document as object
dim dispatcher as object
rem ---------------------------------------------------------------------
rem get access to the document
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ----------------------------------------------------------------------
dim args1(2) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Zoom.Value"
args1(0).Value = 100
args1(1).Name = "Zoom.ValueSet"
args1(1).Value = 28703
args1(2).Name = "Zoom.Type"
args1(2).Value = 0
dispatcher.executeDispatch(document, ".uno:Zoom", "", 0, args1())
For Count = 66 To 841 Step 1
Cell = Sheet.getCellByPosition(0, Count)
IF Cell.Value > 1000 Then
Cell.CellBackColor = RGB(0, 0, 255)
Cell2 = Sheet.getCellByPosition(3, Count)
Cell3 = Sheet.getCellByPosition(5, Count)
Cell4 = Sheet.getCellByPosition(7, Count)
IF Cell3.Type = com.sun.star.table.CellContentType.EMPTY Then
IF Cell4.Value = 0.00 Then
Cell3.CellBackColor = RGB(255, 0, 0)
Cell4.CellBackColor = RGB(255, 0, 0)
ENDIF
ELSE
IF Cell3.Value < 9 AND Cell4.Value > 5 Then
IF Cell2.Value <= 15 Then
Cell2.CellBackColor = RGB(255, 255, 0)
ELSEIF Cell2.Value > 15 AND Cell2.Value <= 40 THEN
Cell2.CellBackColor = RGB(0, 255, 0)
ELSEIF Cell2.Value > 40 THEN
Cell2.CellBackColor = RGB(0, 255, 255)
END IF
Cell3.CellBackColor = RGB(0, 255, 0)
Cell4.CellBackColor = RGB(0, 255, 0)
ELSEIF Cell3.Value >= 80 Then
Cell3.CellBackColor = RGB(0, 255, 255)
End IF
End IF
End IF
Next Count
If (Doc.isModified) Then
If (Doc.hasLocation And (Not Doc.isReadOnly)) Then
Doc.store()
End If
End If
Doc.close(True)
End Sub
而可以用 Tcl/Tk 執行 soffice.exe,來幫我們自動執行這件事:
set DIR [pwd]
set DOCS [glob *.xls]
foreach file $DOCS {
set inputFile $DIR
append inputFile "/" $file
set exeList [list "C:\\Program Files\\OpenOffice.org 3\\program\\soffice.exe" "macro:///Standard.Module1.AutoFindGoodMan($inputFile)"]
exec {*}$exeList
}
但是我還沒有摸索出來在執行的時候不要顯示出來 OpenOffice.Org 文件視窗的方法,不論是使用命令列指定,或者在執行時設定的方式,都是沒有效果的(有可能是因為我沒有設定正確吧……)。
2009-07-30
執行程式
Tcl 使用 exec 來執行外部程式:
set var [list rundll32.exe shell32.dll,Control_RunDLL timedate.cpl,@0,2]
exec {*}$var
這裡使用 {*} 和 exec 結合的範例。
2009-07-17
math function
如果不想寫一堆很長的 name space path,可以這樣做:
namespace path {::tcl::mathop ::tcl::mathfunc}
所以我們就可以這樣做:srand [clock seconds]
這樣不管是撰寫程式還是讀 code 的時候,看起來都比較具可讀性。另外,8.5 同時也 export 出來一些運算子(tcl::mathop)。
puts [* [sqrt 49] [+ 1 2 3]]
也就是,看起來會是類似 lisp 的前序式運算法。
2009-07-16
Access global variables in proc
1. 使用 global 命令宣告要存取的全域變數
2. 在 Tcl 支援 name space 之後,可以使用 name space 的表達方式(::)來存取變數
set x 0
proc appendMe {number} {
global x
incr x $number
}
proc appendMe2 {number} {
incr ::x $number
}
appendMe 3
puts $x
上面就是這二種方式的說明。
2009-07-15
Tcl/Tk 與編碼 (Encoding)
首先是使用者的 Tcl script file 所使用的編碼,可以用下列的方法來指定:
tclsh.exe -encoding [編碼方式] [檔案]
wish.exe -encoding [編碼方式] [檔案]
我們可以使用下面的方式來查詢目前 Tcl/Tk直譯器本身所支援的編碼方式:
encoding names
例如用 Tclkit 來查詢,就可以得到他目前支援的編碼方式:
iso8859-2 iso8859-15 utf-8 ascii cp1252 macRoman koi8-r identity unicode iso8859-1
所以 Tclkit 不支援 BIG5... 如果需要的話要自己加上去。
2009-07-11
GetHomeDir
proc GetHomeDir { } {
global env
# Check if we're using windows
if { [expr [string compare "$::tcl_platform(platform)" "windows" ] == 0] } {
package require registry 1.0
set env_home [registry get {HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders} {Personal}]
set userprofile [set env(USERPROFILE)]
regsub -all {[%]USERPROFILE[%]} $env_home $userprofile env_home
} else {
set env_home $env(HOME)
}
return $env_home
}
另外,如果要刪除 Opera 在 UserProfile 下的 cookie,可以這樣做:
set CookieFile [set env(USERPROFILE)]
append CookieFile {\Application Data\Opera\Opera\profile\cookies4.dat}
if {[file exists $CookieFile]==1} {
file delete $CookieFile
}
因為 AVG 會對這裡一直警告(即使我關掉 Cookie),所以要寫一個小程式殺掉檔案,避免他一直警告(不過話說回來,我已經不用 AVG 了)。
2009-06-28
GIF photo images written with LZW compression
2009-06-27
Scripting: Higher Level Programming for the 21st Century
Scripting language 的缺點就是慢,但是開發快速而且除錯方便,但是當硬體的速度愈來愈快的時候,Scripting language 的缺點也就不太算是缺點了,各種 Scripting language 只會愈來愈重要。
2009-06-25
Try/Catch/Finally syntax
proc read_hex_file {fname} {
set f [open $fname "r"]
set data {}
try {
while { [gets $f line] >= 0 } {
append data [binary format H* $line]
}
} trap {POSIX} {} {
puts "POSIX-type error"
} on error {em} {
error "Could not process file '$fname': $em"
} finally {
close $f
}
}
也就是說,原本 catch 是執行如果出錯,那就依據取得的 error code,再來判斷怎麼處理;而 try/finally 則是如果發生錯誤,會依據 error code 而把程式的流程流向該處理這個錯誤的 error handler,因此整個 code 如果寫的好會看起來比較清晰。對於錯誤的處理策略看起來比較清晰。
2009-06-24
SQLite and PostgreSQL
PostgreSQL 有提供 Tcl 的介面(只是不是使用 TDBC API,而是 specify for PostgreSQL 的),而且需要自己去網站下載相關的檔案。
Google Student Summer 計畫裡,關於 Tcl 的部份,有看到關於 TDBC-PostgreSQL 的部份,只是不知道目前的進度怎麼樣了。
對我而言,SQLite 是單機使用的最佳選擇,而 PostgreSQL 雖然在 Open Source 界使用聲勢上弱於 MySQL,但是我還是最喜歡使用他(好吧,雖然現在因為沒有在寫關於網路和 WEB 的應用,所以沒有在用他了)。 而在甲骨文併購昇陽之後,MySQL 的前途變成了一件不明確的事情(雖然甲骨文不太可能就這樣壞掉自己的聲譽,所以囉),因此版權和 source code 所有權明確的 PostgreSQL 是一個好選擇,特別是當 PostgreSQL 的可靠度其實很可怕的時候(台灣的中鋼就是使用 PostgreSQL 哦)。
However,如果 TDBC-PostgreSQL 出來了,我會稍微測試一下相關的東西,看看這個 TDBC-PostgreSQL driver 的情況,如果有東西給我修改,對我而言比從零開始好,所以我已經放棄了一開始的想法,先從熟悉 TDBC 的方向著手。
另外,在 TDBC 之後,[Incr Tcl] 4.0(這個版本使用 TclOO 全部改寫)已經進入 Tcl core code,將會以 package 的方式存在,在 8.6 beta 2 就會進去了,所以 8.6 beta 2 出來的時候,我也會看看這部份的情況。
看起來 Tcl/Tk 8.6 將會是一個巨大的改版,不管是物件導向套件的引入(TclOO/iTcl),或者是資料庫 API 的統一(TDBC),甚至是引入 zlib 與 png 的支援,都將深刻的改變這個語言,同時也讓這個語言更好用更強壯。
A Slightly Skeptical View on Scripting Languages
A Slightly Skeptical View on Scripting Languages
一篇對於 Scripting Language 的文章。
比較語言的差異與優缺點是浪費時間,因為每個語言都有其優缺點,挑順手的就好了(除非是因為 project 還是 Boss 要求)。
不過就算是現在,我還是覺得 Tcl 很棒(雖然用的人沒有很多),因為 Tcl 的語言規則很簡單但是卻又變化無窮,John Ousterhout 真的好強啊~~~
Tkhtml v3
Tkhtml 是個通過 ACID2,for Tk 可以用來顯示 HTML/CSS 內容的 widget。
下面是在 Tcler's Wiki 上示範使用 Tkhtml 做出一個 Label widget 的範例:
package require Tkhtml 3.0
# Create and populate an html widget.
html .label -shrink 1
.label parse -final {
<b>Hello <i>world</i></b> example
}
# Pack the new html widget
pack .label
bind .label <KeyPress-q> exit
focus .label
Thread and Tcl
package require Thread
catch {console show}
set ::gThread [thread::create {thread::wait} ]
proc printTime { } {
thread::send -async $::gThread { puts stdout [clock format [clock seconds]] }
after 1000 printTime
}
printTime
puts "started test..."
#only needed for tclsh, to keep the interpreter alive and keep the event loop running
vwait forever
在經過一段時間的學習以後,我才慢慢的看懂了 Tcl 的 Thread 擴充套件應該怎麼用才對,相關的資訊可以看 Tcl Threading Model。如果要檢查 tclsh 是不是 build 成支援 thread,則可以用
expr {[info exists ::tcl_platform(threaded)] && $::tcl_platform(threaded)}
來做到。當值為 1 時,表示有支援。
Tcl/TK 8.5 new syntax: {*} 與 Eval
Tcl/Tk 8.5 引進了新的語法 {*},可以用來動態的建立命令執行,可以讓程式看起來更為簡單(使用 eval 會看起來比較複雜)。
我們可以用 Eval 這個指令將參數串接成一個字串後,將字串視為一個 Tcl Script 丟給解譯器去執行。下面是使用 Eval 版:eval button .b $stdargs -text \$mytext -bd $border
{*} 可以將可以將串列的各個值分開為不同的參數,下面是改寫過後的版本:
button .b {*}$stdargs -text $mytext -bd $border
列出目前的磁碟機
set disks [file volumes]
puts "Disks:"
foreach local $disks {
puts " $local --- [file system $local]"
}
在範例中,我們同時也使用了 file system 來取得檔案系統的資料(是 FAT 或者是 NTFS 等資料)。
Tcl/Tk 與 Thread
Tcl/Tk 在自己的 C API 已經有支援 Thread 的 API(編譯的時候要 enable),並且從 8.1 開始就已經是 thread safe 的軟體,而 Thread 這個套件則是讓我們可以透過 Tcl scripting 的方式來操作。
下面是 Tcl C API 關於 Thread 的部份:
Tcl_ConditionNotify, Tcl_ConditionWait, Tcl_ConditionFinalize, Tcl_GetThreadData, Tcl_MutexLock, Tcl_MutexUnlock, Tcl_MutexFinalize, Tcl_CreateThread, Tcl_JoinThread
在 Linux/FreeBSD/UNIX 世界裡,通常是遵循 POSIX 標準,所以是使用 PThread,而 Windows 平台則有自己的一套 API,而 Tcl/Tk 已經幫我們建立了一個中介層,所以不用管底層的差異。