前段時間,在正式項目中使用Python來讀取Excel表格的數據。具體需求是,項目數據庫中有些數據需要根據Excel表格裏面的數據進行一些調整,功能應該比較簡單。爲了學習Python,決定使用Delphi+Python來實現。Delphi中是使用PythonForDelphi控件來加入Python引擎的。實現整個功能用了大半天時間。
delphi項目方面,需要先修改數據表的封裝類,使它能在Python中出現並使用,簡單操作數據表。改了幾個地方:
-
學控件中的Delphi modules工程,在項目中引入Python引擎,加入一個Delphi模塊。
- 將表操作基類改成從TComponent中繼承過來@_@,目的是爲了能在py腳本中直接使用published的屬性;新實現一個該基類的包裝類,繼承自WrapDelphiClasses.TPyDelphiComponent,並註冊到Delphi模塊中。
- 新加個菜單,調用外部的PY腳本。貪簡單,只在該功能的地方加這些代碼,在調用腳本前,註冊了具體的表封裝對象。
Python方面,有兩個自己寫的腳本,其中一個是使用win32com封裝Excel操作的pyExcel.py,簡陋的代碼,夠用就行。另一個是實現具體的功能的腳本,代碼入下:
import time
from pyExcel import PYExcel
import types
from Delphi import *
from pyExcel import PYExcel
import types
from Delphi import *
lDEHs = {}
CR = chr(10)# + chr(13)
CRCR = CR + CR
CR = chr(10)# + chr(13)
CRCR = CR + CR
def AddSpace(aStr):
CR_R = chr(10)
SPACESTR = ' '
return aStr.replace(CR_R, CR_R+SPACESTR)
pass
CR_R = chr(10)
SPACESTR = ' '
return aStr.replace(CR_R, CR_R+SPACESTR)
pass
def setDEFZ(uKW):
deb.Edit()
s1 = deb.DEFZ
uGZNR = AddSpace(s1.decode('gbk'))
uGZNR = u'【工作內容】%s' %(uGZNR)
uDEFZ = u'%s%s【附註說明】%s【勘誤記錄】%s%s' \
%(uGZNR, CRCR, CRCR, uKW, CRCR)
deb.DEFZ = uDEFZ.encode('gbk')
deb.Post()
pass
deb.Edit()
s1 = deb.DEFZ
uGZNR = AddSpace(s1.decode('gbk'))
uGZNR = u'【工作內容】%s' %(uGZNR)
uDEFZ = u'%s%s【附註說明】%s【勘誤記錄】%s%s' \
%(uGZNR, CRCR, CRCR, uKW, CRCR)
deb.DEFZ = uDEFZ.encode('gbk')
deb.Post()
pass
def setDEFZByXls():
global CR, lDEHs
col_DEH = 'A'
col_KW = 'B'
iRow = 0
iEmpty = 0
xl1 = PYExcel()
global CR, lDEHs
col_DEH = 'A'
col_KW = 'B'
iRow = 0
iEmpty = 0
xl1 = PYExcel()
if xl1.FindBook('Sheet1'):
while (iEmpty<10):
iRow += 1
try:
sDEH = str(xl1.getRangeValue(col_DEH + str(iRow)))
pass
except:
sDEH = None
pass
while (iEmpty<10):
iRow += 1
try:
sDEH = str(xl1.getRangeValue(col_DEH + str(iRow)))
pass
except:
sDEH = None
pass
if not sDEH or (sDEH=='') or (sDEH=='None'):
iEmpty += 1
iEmpty += 1
elif deb.Locate('DEH', sDEH):
lDEHs.setdefault(sDEH, sDEH)
s2 = AddSpace(xl1.getRangeValue(col_KW + str(iRow)))
setDEFZ(s2)
lDEHs.setdefault(sDEH, sDEH)
s2 = AddSpace(xl1.getRangeValue(col_KW + str(iRow)))
setDEFZ(s2)
def setOthers():
global lDEHs
deb.First()
while not deb.Eof():
if not lDEHs.has_key(deb.deh):
lDEHs.setdefault(deb.deh, deb.deh)
try:
setDEFZ(u'')
except:
pass
deb.Next()
global lDEHs
deb.First()
while not deb.Eof():
if not lDEHs.has_key(deb.deh):
lDEHs.setdefault(deb.deh, deb.deh)
try:
setDEFZ(u'')
except:
pass
deb.Next()
setDEFZByXls()
setOthers()
setOthers()
在編寫調試這個腳本用了大半的時間,其中碰到些問題:
- 編碼問題。好在前段時間剛理解Unicode的含義,現在在實際中解決了這個問題。Delphi中的String保存的中文信息,通常都是使用系統的默認字符集來編碼的。從Delphi中取出String如:s1 = deb.DEFZ,s1這時的編碼是系統默認字符集(gbk)。在py腳本中使用代碼:s1.decode('gbk')進行解碼,得到Unicode字符串。保存回Delphi中時,再將Unicode使用gbk編碼:deb.DEFZ = uDEFZ.encode('gbk')。
- PythonforDelphi控件,使用Delphi的Rtti技術,py腳本中能直接使用部分published的屬性,簡化了許多工作量。不過published的方法、過程和數組屬性還是不能直接使用,需要在對應的封裝類中自己包裝。
- 使用PyScripter工具編寫該腳本,很方便。不過當前好象還沒有什麼好的方法來調試以這種運行方式運行的腳本。現在PyScripter支持遠程調試功能,以後有空要想辦法解決這個問題。