VFP 愛用者社區 首頁 VFP 愛用者社區
本討論區為 Visual Foxpro 愛用者經驗交流的地方, 請多多利用"搜尋"的功能, 先查看看有無前例可循, 如果還有不懂的再發問. 部份主題有附加檔案, 須先註冊成為社區居民才可以下載.
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入

採用Word更好地輸出VFP報表

 
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區
上一篇主題 :: 下一篇主題  
發表人 內容
Ruey



註冊時間: 2003-03-12
文章: 1698
來自: tunglo

第 1 樓

發表發表於: 星期三 八月 13, 2003 11:22 am    文章主題: 採用Word更好地輸出VFP報表 引言回覆

採用Word更好地輸出VFP報表
( 作者: 不詳 )


一、概述
無論是西文還是中文Visual FoxPro 3.0(以下簡稱VFP),其報表輸出都有一個嚴重缺陷,就是當資料庫的某一欄位具有溢出延伸屬性(就是當欄位的內容長於指定的輸出寬度時,自動進行換行的屬性)時,在換行處容易出現半個漢字,使輸出的報表內容出現"亂碼"。
另外,VFP與其他資料庫管理系統一樣,報表輸出模組也存在以下嚴重不足:
①報表輸出的寬度和長度不能由用戶改變,無法實現頁面的任意變化;
②由於資料庫中資料的長度不一,必然會導致輸出報表中各欄位元的寬度不適,系統無法根據資料庫的實際內容對輸出的各欄位的寬度進行隨機調整,報表的整體效果差;
③報表一旦輸出,用戶不能對報表格式進行編輯;
④不宜實現對某些特定欄位元的單獨輸出或組合輸出。
爲此,筆者利用VFP的OLE自動化技術,通過Microsoft Word 6.0 提供的Word.Basic物件,將資料庫的記錄輸出成Word文檔。


二、在VFP中自動生成Word文檔的基本原理和方法
1.用Word.Basic生成資料Word文檔的基本原理我們知道,Windows的OLE技術是在兩個具有OLE能力的應用程式之間建立了一種資訊共用機制。能夠提供OLE服務的應用程式叫伺服器,請求OLE服務的應用程式叫客戶機。由於VFP不能爲其他具有OLE能力的應用程式提供可用的物件,不能作爲OLE伺服器。爲了在VFP中使用OLE自動化技術來解決報表輸出存在的問題,必須在Windows環境下選擇一個能作爲OLE伺服器的應用程式。Microsoft Word 6.0不僅能夠向VFP提供OLE物件類型Word.Basic,而且能夠生成複雜的表格,具有較強的編輯功能,是生成資料庫報表的理想工具。
VFP和Microsoft Word 6.0之間的資訊共用機制是通過在VFP中創建由MS Word 6.0提供可用OLE物件Word.Basic實現的。因此,要使用OLE自動化技術,必須首先使用VFP的OLE物件創建函數CREATEOBJECT() 創建MS Word 6.0的OLE物件,即: oleWord=CREATEOBJECT("Word.Basic")

2.用Word.Basic生成資料Word文檔的基本方法在用CREATEOBJECT()函數創建OLE物件之後,我們就可以利用面向物件的程式設計方法,調用Word.Basic的具體命令,將資料庫的具體內容生成到Word文檔。
用Word.Basic生成資料庫的Word文檔,常用的方法有兩種:第一種方法是用Word.Basic的一系列命令生成資料庫的整個Word文檔;另一種方法是利用Word.Basic打開預製的基本文檔框架,再用Word.Basic的編輯命令來生成資料庫的Word文檔。這兩種方法各有優點,有時要將它們結合起來使用。第一種方法主要用於對資料庫報表沒有任何要求的全自動生成,由於採用全自動生成技術,儘管也能實現輸出頁面的任意變化和報表中各欄位元寬度的自動調整等功能,但不能直接根據具體的資料庫輸出具有相應特色的標題。第二種方法在標題及輸出的格式上具有更大的靈活性。通常情況下,先用第一種方法輸出某些資料庫的一般文檔,再利用W ord將其修改成特殊報表輸出的基本文檔框架,供第二種方法使用。
下面結合應用介紹第二種方法的具體實現和主要演算法。
(1) 定制基本的Word文檔框架
在基本的文檔框架中可以包含Word文檔的任何內容,比如在標題的兩邊各插入一些圖片等等。但是爲了實現對資料庫欄位的定位輸出,該文檔框架必須包含一個表,該表的表頭可以設計成任何複雜的形式, 如下面的文檔框架:
表1 不良地質:瓦斯資訊
爲了能使Word.Basic將資料庫中要輸出的欄位正確地輸出到基本框架中,在基本框架中需要增加位置標記。我們可以用在Word基本文檔框架中添加書簽的方法來指導Word.Basic在基本框架中的正確定位,這些書簽分別添加在基本文檔框架中僅有的一行表體的各欄位處。由於Word.Basic在進行後續記錄的輸出時是按第一表體行中輸出欄位的順序進行輸出的,這樣就可以保證後續各行輸出的正確性了。爲了方便起見可將書簽名定義成與欄位名同名。
在實際的資料輸出過程中,由於我們允許輸出頁面任意變化,並允許對輸出的各欄位寬度進行優化調整,這樣就很難保證各頁的行數相同。爲了使輸出頁面的標題能夠正確地列印在每一輸出頁面的首部,將該表的表頭設置成"標題允許"(先選定要設置成標題允許的一行或多行,再用"表格"功能表中的"標題"命令進行設置)。爲了使輸出頁面的高度一致,可用"表格"功能表中"單格高度和寬度"對話方塊選擇"允許跨頁斷行"選項,當然也可用Word.Basic的TableR owHeight命令對"允許跨頁斷行"進行設置。
另外,在定義基本文檔框架時,不必考慮總的表格寬度應放大至何種尺寸以及各欄位元之間的比例關係,僅僅需要將各欄位元的寬度定義成用戶所想要的最小寬度即可,其具體目的在下面的資料庫輸出的主要演算法中會作解釋。
(2) 生成Word文檔的主要演算法
在用Word.Basic將資料庫的記錄輸出成Word文檔時,需要編程調整輸出報表的頁面和各欄位元的寬度,下面介紹編程中使用的調整策略和主要演算法。
由於資料庫中資料的隨機性,特別是字元型和備註型資料長度的不定性,表中各欄位元寬度的比例關係很難預先確定,需要在整個報表生成之後進行調整。調整的基本策略是先將各記錄中要輸出的欄位的具體內容輸出到表格中,並在輸出過程中記下每一欄位在各行中的最大寬度(字元數),用它作爲調整各欄位元寬度比例關係的依據。如果完全按照此依據進行調整,表體部分一定能編排得比較勻稱,但表頭部分的編排有可能發生變化(如上面的"採取措施"表頭,由於資料庫中該欄位對應的內容可能很少,在進行欄位寬度調整時,有可能使表頭文字變成 多行排列),報表的整體效果仍然較差。所以有必要預先知道各欄位的最小寬度,以防止在調整各欄位寬度時表頭多行排列。爲此,約定原始文檔框架中各欄位的寬度即爲最小寬度,且欄位元寬度調整僅對字元型和備註型欄位進行。
基於上述調整策略,我們介紹相應的演算法。爲了便於介紹,我們假設通過頁面和頁邊距的設置得出需要將表格的寬度調寬至nWidth英寸,並定義如下資料類型:
LOCAL aFieldName[nOutColumn,6]
其中:
nOutColumn爲要輸出欄位個數,也是表格的最大列數;
aFiledName[nOutColumn,1]爲書簽名;
aFiledName[nOutColumn,2]爲該書簽所在欄位元對應欄位的欄位類型;
aFiledName[nOutColumn,3]爲該書簽所在欄位元對應欄位的欄位寬度;
aFiledName[nOutColumn,4]爲該書簽所在欄位元對應欄位的小數位數;
aFiledName[nOutColumn,5]爲該書簽所在欄位元最小TWIP數;(1英寸 =1440 TWIP)
aFiledName[nOutColumn,6]爲該書簽所在欄位元在各行中的最大字元個數。
這樣在計算出各欄位元的最大字元個數和各欄位元的最小TWIP數後,就可以計算出需要調整欄位元的總字元數和可供使用的寬度總TWIP數。
假設可供使用的寬度總數爲j(TWIP),需要調整欄位元的總字元數爲(字元),則某要調整欄位的寬度應爲: j/k*aFieldName[i,6] 式中i爲該調整欄在表中的列號。 但是該寬度有可能小於該欄位的最小寬度,這樣該欄位就不應調 整,需要將該欄的類型a FieldName[i,2]修改爲"U"(非C且非M即可), 而將該欄位列入非調整的行列,同時也要相應修改j和k,再從第一列逐 一檢查,查看是否仍有這樣的列,如果有需要再重復上述步驟。直到不 再有上述類型的列爲止。最後再用TableColumnWidth命令對剩下需要 調整的欄位元進行調整即可。
三、生成Word文檔的程式實現 根據上面的調整策略和演算法,我們給出用VFP編制的從VFP資料庫 輸出Word文檔的通用程式。此程式不依賴具體的資料庫結構,也不依賴於具體的報表輸出格式,可用於任何VFP資料庫的Word文檔輸出。

LOCAL nOldrecno,oleWord,i,j,k,nOutColumn,cString
LOCAL aFieldList[1]
USE b1
IF EOF() &&無輸出結果則直接返回
RETURN
ENDIF
=AFIELDS(aFieldList) &&將當前資料庫的欄位資訊存入陣列中
nOldrecno=RECNO()
*下面首先生成Word.Basic物件,再用Word.Basic的打開文檔命令
打開基本文檔框架
oleWord=CREATEOBJECT("Word.Basic")
oleWord.FileOpen("c:\mf\data\word.doc")
*下面是從Word文檔的首部向下移動插入點指標,直到移動到表格
中爲止。
*這樣做的原因是,基本文檔框架中在表格的上面可以有附加內容。
DO WHILE oleWord.SelInfo(12)#-1
oleWord.LineDown
ENDDO
*下面是檢查書簽數與表格的最大列數是否相同
nOutColumn=oleWord.CountBookMarks()
IF nOutColumn#oleWord.SelInfo(18 )
oleWord.AppClose("Microsoft Word")
=MESSAGEBOX("書簽與表格的列數不符",16,"提示資訊")
RETURN
ENDIF
*下面是定義列資訊陣列,並且填寫該陣列的前4列內容
LOCAL aFieldName[nOutColumn,6]
*-- aFieldName列的意義:1書簽名,2欄位類型,3欄位寬度,4,小
數位數,
*-- 5原始表中各列寬度的最小TWIP數
*-- 6在具體的填寫過程中該書簽所在列的所有行中的字元的最
大個數
FOR i=1 to nOutColumn
aFieldName[i,1]=oleWord.BookMarkName(i)
FOR j = 1 TO FCOUNT()+1
IF j=FCOUNT()+1
oleWord.AppClose("Microsoft Word")
=MESSAGEBOX("標簽名:"+aFieldName[i,1];
+"不是資料庫的欄位名",16,"
提示資訊")
RETURN
ENDIF
IF UPPER(aFieldName[i,1])==UPPER(ALLT(aFieldLis
t[j,1]))
aFieldName[i,2]=aFieldList[j,2] &&類型
aFieldName[i,3]=aFieldList[j,3] &&寬度
aFieldName[i,4]=aFieldList[j,4] &&小數位
EXIT
ENDIF
ENDFOR
ENDFOR
*將插入點移到表格最底行的最右端
DO WHILE oleWord.SelInfo(12)=-1
oleWord.LineDown
ENDDO &&按下箭頭向下移出表格
DO WHILE oleWord.SelInfo(12)#-1
oleWord.CharLeft
ENDDO &&按左箭頭移到表格最後一列的末尾處
IF oleWord.SelInfo(16)#oleWord.SelInfo(18 )+1
oleWord.AppClose("Microsoft Word")
=MESSAGEBOX("未能移到表格最後列的尾部",16,"提示資訊")
RETURN
ENDIF
*--下面計算原始表格中各列的寬度,即列的最小寬度(以TWIP爲
單位)
j=oleWord.SelInfo(5)
FOR i=nOutColumn TO 1 STEP -1
oleWord.PrevCell
k=oleWord.SelInfo(5)
aFieldName[i,5]=j-k
aFieldName[i,6]=0
j=k
ENDFOR
IF oleWord.SelInfo(16)#1
oleWord.AppClose("Microsoft Word")
=MESSAGEBOX("最後不是移到表格列的首列",16,"提示資訊")
RETURN
ENDIF
*各列的最小寬度計算完畢
*下面表格填寫具體內容,
*並且在填寫具體內容時將各列的最大字元數記錄到aFieldName[
i,6]中
LOCATE
oleWord.EditGoto((aFieldName[1,1]))
oleWord.PrevCell()
DO WHILE !EOF()
FOR i=1 TO nOutColumn
DO CASE
CASE aFieldName[i,2]=="N"
cString=STR(&aFieldName[i,1],aFieldName[i,3],
aFieldName[i,4])
CASE aFieldName[i,2]=="I"
cString=ALLT(STR(&aFieldName[i,1],10,0]))
CASE aFieldName[i,2]=="C" OR aFieldName[i,2]=="M"
cString=TRIM(&aFieldName[i,1])
IF LEN(cString)>aFieldName[i,6]
aFieldName[i,6]=LEN(cString)
ENDIF
OTHERWISE
cString="暫不處理類型"
ENDCASE
oleWord.NextCell()
oleWord.Insert((cString)) &&字元型變數必須外加()
ENDFOR
SKIP
ENDDO
*--表格內容填寫完畢
*下面根據填寫的具體內容重新調整表格某些列的寬度
*(在下面的計算過程中單位爲TWIP)
j=nWidth*1440 &&nWidth爲版心寬度是一總體變數,單位爲英寸
&&1英寸=1440TWIP
k=0
FOR i=1 TO nOutColumn
IF aFieldName[i,2]#"C" AND aFieldName[i,2]#"M"
j=j-aFieldName[i,5] &&剩餘可用寬度
ELSE
k=k+aFieldName[i,6] &&需要調整寬度的最大
字元數之和
ENDIF
ENDFOR &&減去禁止調列的寬度
FOR i=1 TO nOutColumn
IF aFieldName[i,2]="C" OR aFieldName[i,2]="M"
*如果要調整的寬度小於或等於最小寬度,則將其列入非調整之列
IF j/k*aFieldName[i,6] <= aFieldName[i,5]
aFieldName[i,2]="U"
j=j-aFieldName[i,5]
k=k-aFieldName[i,6]
i=1 &&從頭迴圈
LOOP
ENDIF
ENDIF
ENDFOR
FOR i=1 TO nOutColumn
IF aFieldName[i,2]="C" OR aFieldName[i,2]="M"
oleWord.EditGoto((aFieldName[i,1]))
oleWord.TableSelectColumn
oleWord.TableColumnWidth(j/k*aFieldName[i,6]/20,2,
0,0,0,0)
*1磅=20TWIP,TableColumn()的缺省單位爲磅
ENDIF
ENDFOR
*寬度調整完畢
oleWord.FileSaveAs("c:\mf\data\word2.doc")
*oleWord.FilePrint(0,0,0,"","","",0,1,"",0,0,0,"")
oleWord.AppClose("Microsoft Word")
WAIT "卸載Word BAsic" WINDOW NOWAIT
WAIT CLEAR
RETURN
在將資料庫內容生成Word文檔的最終結果一種方法是以文檔的形
式保存下來,另一方法是不僅要把文檔保存下來,還要進行列印,此時
需要注意的一點是:不能採用幕後列印,將上述程式的中*olwWord.Fil
ePrint(0,0,0,"","","",0,1,"",0,0,0,"")前面的星號"*"去掉即可

_________________
#############################
快樂媽咪系列幸福宅配,喝十全雞湯~原來幸福那麼簡單!!

學會VFP使用者社區的搜尋,Code才會更有趣~
#############################
回頂端
檢視會員個人資料 發送私人訊息
從之前的文章開始顯示:   
發表新主題   回覆主題    VFP 愛用者社區 首頁 -> VFP 討論區 所有的時間均為 台北時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
無法 在這個版面附加檔案
無法 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作