2009-08-02

在命令列呼叫 OpenOffice.Org Basic 巨集

這不只可以用 Tcl/Tk 來做到,只是我最習慣 Tcl/Tk 來做這些事情。

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

在 Tcl 8.5 以前,Tcl 的數學運算都是透過 expr 這個 command 做到的,而在 8.5 則引進了 tcl::mathfunc,讓使用一些數學運算的 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

在 procedure 裡存取全域變數,有二種做法:

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 的編碼,可以分為二部份,一部份是 Tcl/Tk 直譯器本身支援的編碼,一部份是使用者的 Tcl script file 所使用的編碼。

首先是使用者的 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

在 Windows,我們可以透過謮取 registry 和環境變數拿到使用者的 My Documents. 下面是來自於 Tcler' Wiki 的 code,只是我自己有小修改一些,好符合我自己的環境。
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

Tk 在 8.6 除了加入 PNG 格式的支援,同時因為 LZW 演算法專利已經過期,所以 Tk 8.6 也會加入 GIF photo images written with LZW compression 的支援。
下面是一些資訊:
"Unisys U.S. LZW Patent No. 4,558,302 expired on June 20, 2003, the counterpart patents in the United Kingdom, France, Germany and Italy expired on June 18, 2004, the Japanese counterpart patents expired on June 20, 2004 and the counterpart Canadian patent expired on July 7, 2004."
IBM 也握有 LZW 的專利,但是根據 GNU GIF 的網頁,IBM 的專利也將於 2006/10 到期,也就是說,實作的人將不用擔心觸碰到 LZW 專利地雷。
雖然我們有了 PNG,但是能夠使用 GIF 也不錯。

2009-06-27

Scripting: Higher Level Programming for the 21st Century

這是由 John K. Ousterhout 所寫的文章,而從現在 PHP/Perl/Python/Ruby/Tcl 各種 scripting language 的發展來看,似乎也是如 John K. Ousterhout 所推測的一樣。當然,自由軟體所帶來的效應,可能也是其中的一個原因之一。

Scripting language 的缺點就是慢,但是開發快速而且除錯方便,但是當硬體的速度愈來愈快的時候,Scripting language 的缺點也就不太算是缺點了,各種 Scripting language 只會愈來愈重要。

2009-06-25

Try/Catch/Finally syntax

Tcl 原本就有錯誤處理的機制(使用 catch),而在 TIP #329  (in 8.6 b1)又加入了類似 Try/Catch/Finally 來增強原本的機制。
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

雖然 Tcl 在 8.6 終於加入了 TDBC,但是目前只有支援 SQLite, MySQL 等少數的資料庫,而沒有支援 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 的支援,都將深刻的改變這個語言,同時也讓這個語言更好用更強壯。