相關元件:WordApplication, WordDocument, DBLookUPCombobox, ADOConnection, ADOQuery,Button。
假如各位讀者,讀完了前面兩篇Delphi & Word以後,相信對Word的基本控制,已經有一定的瞭解,再來就是對於Word與資料庫所產生報表的相關運用罷了,本篇以Delphi所附的Access資料庫,與已經設計好的Word文件(可以由使用者自行設計,設計完成後再交予程式設計者),進行報表的套表。
1. 程式預覽:本篇主要是利用DBLookUPComBobox來做為資料範圍的選取(如圖25),然後分成兩個範例,利用相同的資料,對於事先已經完成的Word文件(圖26,27)做套表的動作。
圖25,程式畫面
圖26,Word文件一
圖27,佈滿整頁的Word文件
2. 資料庫設計:本程式為Master-Detail的資料庫,兩個ADOQuery的SQL語法如下
主檔(Master):請注意中間的空白為用來填入DBLookUPCombobox選取的內容,假如使用未選取,怎為空白,表示選取全部,此為筆者報表程式設計的方式,各位讀者可以參考使用
select a.OrderNo,a.CustNo,a.empno,c.LastName,c.FirstName,a.SaleDate,a.ShipDate,a.ShipVIA,a.Freight,b.Company,
b.Addr1,b.Addr2,b.City,b.State,b.Zip,b.Country
from orders a,CUSTOMER b,EMPLOYEE c
where a.custno=b.custno and a.empno=c.empno
order by a.orderNO
次檔(Detail)
select a.PartNo,a.OrderNO,b.Description,a.Qty,b.ListPrice,a.Discount,a.qty*b.ListPrice*(100-a.discount)/100 as amount
from ITEMS a,PARTS b
where a.PartNO=b.PartNO and a.orderno=:orderNO
3. 程式設計:
a. 當使用者選取起始編號與終止編號時,紀錄選取的資料
procedure TForm1.DBLookupComboBox1CloseUp(Sender: TObject);
begin
qs1:=DBLookupComboBox1.Text;
end;
procedure TForm1.DBLookupComboBox2CloseUp(Sender: TObject);
begin
qs2:=DBLookupComboBox2.Text;
end;
b. 按下InVoice1 Button(使用Invoice.doc)
procedure TForm1.Button1Click(Sender: TObject);
var Template,ItemIndex,_Type:OleVariant;
s:string;
i,j,k:integer;
sum:real;
begin
_Type:=wdSectionBreakNextPage;
s:=extractfilepath(application.ExeName)+'invoice.doc';
if Fileexists(s) then
begin
//開啟Word檔案
Template:=s;
WordApplication1.Documents.Open(template,EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam);
//第一個Word檔案連接,對於Word來說,新產生的檔案ItemIndex再第一個
ItemIndex:=1;
WordDocument1.ConnectTo(WordApplication1.Documents.Item(ItemIndex));
//顯示Word檔案,假如已經有其他word文件開啟,則不會有動作
WordApplication1.Visible:= True;
//先將整個Word文件複製:在進行Word多頁套表設計時,必須先將Word表格複製,當超過一頁時,再將表格貼上,不過為避免上下頁表格連接,兩個表格間必須有一空白行,以免造成Word視為一個表格,同時也造成版面的問題,因此,在程式開始時,將Word表格先剪下,使整個Word文件,剩下變成一個Enter,在程式開始後,再將表格貼上,如此整個Word文件會多出一個Enter,在程式結束前,將其刪除。
WordDocument1.Range.Select;
WordDocument1.Range.Cut;
//查詢條件輸入
ADOQuery1.Active:=false;
if qs1='' then
ADOQuery1.SQL.Strings[3]:=''
else
ADOQuery1.SQL.Strings[3]:=' and a.OrderNo>='+qs1;
if qs2='' then
ADOQuery1.SQL.Strings[4]:=''
else
ADOQuery1.SQL.Strings[4]:=' and a.OrderNo<='+qs2;
ADOQuery1.active:=true;
ADOQuery2.Active:=true;
ADOQuery1.First;
i:=0; //table 數
while not ADOQuery1.Eof do
begin
//將表格貼上
Worddocument1.Range.Characters.Last.select;
Worddocument1.Range.Characters.Last.paste;
i:=i+1;
if i>1 then //插入分頁符號
begin
WordDocument1.Tables.Item(i).Select;
WordApplication1.Selection.InsertBreak(_Type);
end;
WordDocument1.Tables.Item(i).Cell(1,1).Select;
//用置換的方法,置換Master的資料,repl函數,請參考後面說明
repl('Company_name',ADOQuery1.fieldbyname('company').asstring);
repl('Address1',ADOQuery1.fieldbyname('Addr1').asstring+','+ADOQuery1.fieldbyname('Addr2').asstring);
repl('Address2',ADOQuery1.fieldbyname('City').asstring+','+ADOQuery1.fieldbyname('State').asstring+','+
ADOQuery1.fieldbyname('Zip').asstring);
repl('Address3',ADOQuery1.fieldbyname('Country').asstring);
//固定的Master表格資料
WordDocument1.Tables.Item(i).Cell(3,1).Range.Text:=ADOQuery1.fieldbyname('OrderNO').asstring;
WordDocument1.Tables.Item(i).Cell(3,2).Range.Text:=ADOQuery1.fieldbyname('CustNO').asstring;
WordDocument1.Tables.Item(i).Cell(3,3).Range.Text:=ADOQuery1.fieldbyname('LastName').asstring+
' '+ADOQuery1.fieldbyname('FirstName').asstring;
WordDocument1.Tables.Item(i).Cell(3,4).Range.Text:=ADOQuery1.fieldbyname('SaleDate').asstring;
WordDocument1.Tables.Item(i).Cell(3,5).Range.Text:=ADOQuery1.fieldbyname('ShipDate').asstring;
WordDocument1.Tables.Item(i).Cell(3,6).Range.Text:=ADOQuery1.fieldbyname('ShipVia').asstring;
j:=5;
sum:=0;
//Detail資料填入
While not ADOQuery2.Eof do
begin
WordDocument1.Tables.Item(i).Cell(j,1).Range.Text:=ADOQuery2.fieldbyname('PartNO').asstring;
WordDocument1.Tables.Item(i).Cell(j,2).Range.Text:=ADOQuery2.fieldbyname('Description').asstring;
WordDocument1.Tables.Item(i).Cell(j,3).Range.Text:=ADOQuery2.fieldbyname('Qty').asstring;
WordDocument1.Tables.Item(i).Cell(j,4).Range.Text:=formatfloat('###,###.#0',
ADOQuery2.fieldbyname('ListPrice').asfloat);
WordDocument1.Tables.Item(i).Cell(j,5).Range.Text:=formatfloat('###,###.##',
ADOQuery2.fieldbyname('Discount').AsFloat);
WordDocument1.Tables.Item(i).Cell(j,6).Range.Text:=formatfloat('###,###.#0',
ADOQuery2.fieldbyname('amount').AsFloat);
sum:=sum+ADOQuery2.fieldbyname('amount').AsFloat;
WordDocument1.Tables.Item(i).Cell(j,6).select;
j:=j+1;
ADOQuery2.Next;
if not ADOQuery2.Eof then
insertoneline; //插入一行
end;
WordDocument1.Tables.Item(i).Cell(j,2).Range.Text:=formatfloat('###,###.#0',sum);
WordDocument1.Tables.Item(i).Cell(j+1,2).Range.Text:=formatfloat('###,###.#0',
ADOQuery1.fieldbyname('Freight').AsFloat);
WordDocument1.Tables.Item(i).Cell(j+2,2).Range.Text:=formatfloat('###,###.#0',
sum+ADOQuery1.fieldbyname('Freight').AsFloat);
ADOQuery1.Next;
end;
//刪除最號的enter
WordDocument1.Range.Characters.Last.Delete(emptyparam,ItemIndex);
WordDocument1.Disconnect;
WordApplication1.Disconnect;
ADOQuery1.Active:=false;
ADOQuery1.SQL.Strings[3]:='';
ADOQuery1.SQL.Strings[4]:='';
ADOQuery1.Active:=true;
end else
begin
showmessage('無法找到'+s);
end;
end;
請注意,在以上的方式中,筆者並未控制當Detail資料超過一頁時的結果
c. 按下InVoice2 Button(使用Invoice2.doc)
procedure TForm1.Button2Click(Sender: TObject);
var Template,ItemIndex:OleVariant;
s:string;
i,j,k:integer;
sum:real;
begin
s:=extractfilepath(application.ExeName)+'invoice2.doc';
if Fileexists(s) then
begin
Template:=s;
WordApplication1.Documents.Open(template,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam,EmptyParam);
ItemIndex:=1;
WordDocument1.ConnectTo(WordApplication1.Documents.Item(ItemIndex));
WordApplication1.Visible:= True;
WordDocument1.Range.Select;
WordDocument1.Range.Cut;
ADOQuery1.Active:=false;
if qs1='' then
ADOQuery1.SQL.Strings[3]:=''
else
ADOQuery1.SQL.Strings[3]:=' and a.OrderNo>='+qs1;
if qs2='' then
ADOQuery1.SQL.Strings[4]:=''
else
ADOQuery1.SQL.Strings[4]:=' and a.OrderNo<='+qs2;
ADOQuery1.active:=true;
ADOQuery2.Active:=true;
ADOQuery1.First;
i:=0; //table 數
while not ADOQuery1.Eof do
begin
Worddocument1.Range.Characters.Last.select;
Worddocument1.Range.Characters.Last.paste;
i:=i+1;
WordDocument1.Tables.Item(i).Cell(1,1).Select;
repl('Company_name',ADOQuery1.fieldbyname('company').asstring);
repl('Address1',ADOQuery1.fieldbyname('Addr1').asstring+','+ADOQuery1.fieldbyname('Addr2').asstring);
repl('Address2',ADOQuery1.fieldbyname('City').asstring+','+ADOQuery1.fieldbyname('State').asstring+','+
ADOQuery1.fieldbyname('Zip').asstring);
repl('Address3',ADOQuery1.fieldbyname('Country').asstring);
WordDocument1.Tables.Item(i).Cell(3,1).Range.Text:=ADOQuery1.fieldbyname('OrderNO').asstring;
WordDocument1.Tables.Item(i).Cell(3,2).Range.Text:=ADOQuery1.fieldbyname('CustNO').asstring;
WordDocument1.Tables.Item(i).Cell(3,3).Range.Text:=ADOQuery1.fieldbyname('LastName').asstring+
' '+ADOQuery1.fieldbyname('FirstName').asstring;
WordDocument1.Tables.Item(i).Cell(3,4).Range.Text:=ADOQuery1.fieldbyname('SaleDate').asstring;
WordDocument1.Tables.Item(i).Cell(3,5).Range.Text:=ADOQuery1.fieldbyname('ShipDate').asstring;
WordDocument1.Tables.Item(i).Cell(3,6).Range.Text:=ADOQuery1.fieldbyname('ShipVia').asstring;
j:=5;
sum:=0;
While not ADOQuery2.Eof do
begin
WordDocument1.Tables.Item(i).Cell(j,1).Range.Text:=ADOQuery2.fieldbyname('PartNO').asstring;
WordDocument1.Tables.Item(i).Cell(j,2).Range.Text:=ADOQuery2.fieldbyname('Description').asstring;
WordDocument1.Tables.Item(i).Cell(j,3).Range.Text:=ADOQuery2.fieldbyname('Qty').asstring;
WordDocument1.Tables.Item(i).Cell(j,4).Range.Text:=formatfloat('###,####.#0',
ADOQuery2.fieldbyname('ListPrice').asfloat);
WordDocument1.Tables.Item(i).Cell(j,5).Range.Text:=formatfloat('###,####.##',
ADOQuery2.fieldbyname('Discount').AsFloat);
WordDocument1.Tables.Item(i).Cell(j,6).Range.Text:=formatfloat('###,####.#0',
ADOQuery2.fieldbyname('amount').AsFloat);
sum:=sum+ADOQuery2.fieldbyname('amount').AsFloat;
j:=j+1;
ADOQuery2.Next;
end;
WordDocument1.Tables.Item(i).Cell(30,2).Range.Text:=formatfloat('###,####.#0',sum);
WordDocument1.Tables.Item(i).Cell(31,2).Range.Text:=formatfloat('###,####.#0',
ADOQuery1.fieldbyname('Freight').AsFloat);
WordDocument1.Tables.Item(i).Cell(32,2).Range.Text:=formatfloat('###,####.#0',
sum+ADOQuery1.fieldbyname('Freight').AsFloat);
ADOQuery1.Next;
end;
WordDocument1.Range.Characters.Last.Delete(emptyparam,ItemIndex);
WordDocument1.Disconnect;
WordApplication1.Disconnect;
ADOQuery1.Active:=false;
ADOQuery1.SQL.Strings[3]:='';
ADOQuery1.SQL.Strings[4]:='';
ADOQuery1.Active:=true;
end else
begin
showmessage('無法找到'+s);
end;
end;
d. repl函數
procedure TForm1.repl(source,repl_text:string);
var _Text,_MatchCase,_MatchWholeWord,_MatchWildcards,_MatchSoundsLike,
_MatchAllWordForms,_Forward,_Wrap,_Format,_ReplaceWith,_Replace,
_MatchKashida,_MatchDiacritics,_MatchAlefHamza,_MatchControl:OleVariant;
begin
WordApplication1.Selection.Find.ClearFormatting;
_Text :=source;
_MatchCase := False;
_MatchWholeWord := False;
_MatchWildcards := False;
_MatchSoundsLike := False;
_MatchAllWordForms:=EmptyParam;
_Forward := True;
_Wrap := wdFindContinue;
_Format := False;
_Replace:=wdReplaceOne;
_ReplaceWith:=repl_text;
_MatchKashida:=EmptyParam;
_MatchDiacritics:=EmptyParam;
_MatchAlefHamza:=EmptyParam;
_MatchControl:=EmptyParam;
WordApplication1.Selection.Find.Execute(_Text,_MatchCase,_MatchWholeWord,
_MatchWildcards,_MatchSoundsLike,_MatchAllWordForms,_Forward,_Wrap,
_Format,_ReplaceWith,_Replace,_MatchKashida,_MatchDiacritics,
_MatchAlefHamza,_MatchControl);
end;
e. 插入一行函數
procedure TForm1.insertoneLine;
var _NumberRows:OleVariant;
begin
_NumberRows:=1;
WordApplication1.Selection.InsertRowsBelow(_NumberRows);
end;