当前位置:首页 > 科技 > 正文

Delphi控制Word编程手记

  前几日对软件“文件整理助手”进行了完善。该软件有文本文件合并,文本文件内容的替换、插入、删除、为特定行首/尾添加字符、清理空行等,以及文件批量替换、改名等功能。
  一同事见后,希望能对Word文件进行合并。尽管Word的“插入文件”可以实现这个功能,但不能在插入文件时调整插入的顺序,也不能控制插入的新文件是否另起一页。Word虽然功能强大,但还是有一定的局限性。当然,通过VBA录入脚本、编写宏代码也许可以实现这些复杂的功能。但囿于其缺乏通用性和移植性,对于不善于编程的人来说,还是存在诸多不便。
  因此,打算做一个“Word文档合并器”。刚做出这个决定时,以为很简单,因为Delphi的Servers组件页有WordApplication、WordDocument等控件,通过它们来控制全不是那么回事!以前做过涉及到Excel的小程序,没觉得有多难。首次跟Word打交道,竟给我来了个大大的下马威。
  以前用过函数,用过过程,也用过带参数的函数、带参数的过程。见过参数多的,但没见过打开、保存Word时尽然要用多达15个、16个参数的函数、过程。而且这些参数青一色地被定义为OleVariant类型,哪些应该是字符串,哪些应该是布尔型,或者专门为Word程序和文档定义的变量类型,没有详细的、系统的资料,只好摸着石头过河,慢慢研究了。
  经过几翻碰壁、几翻查证、几翻试验,把要实现的功能一步步拆解,逐一进行调试,通过后再重新组合起来试验。经过拆解、调试、组装三步曲之后,总算是完成了“Word文档合并器”这样一个小小的软件。
  为避免下次还重复这种繁琐的基础工作,现将有关技术要点总结于下:
  (本程序在Word2003中调试通过,其他版本未进行测试。网上找的一些资料在过程调用、函数语句及参数个数上有出入,可能与Word版本不一样有关。)
说明:
  主窗体中放置以下三个与Word有关的控件:
Word: TWordApplication; //Word应用程序接口
Document1: TWordDocument; //Word文档
  ole_ShowDoc: TOleContainer; //用以显示Word文档

【一】相关Word组件
  这里仅整理Delphi通过自身所提供的Server组件连接Office(Word)的有关资料,其他方法暂不研究。Delphi中提供的与操作Word有关的组件有共有5个,常用的有4个:
  1、TWordApplication对象。对应于Microsoft Word应用程序,主要用来在Delphi程序中直接启动或关闭Word应用程序,建立或断开与Word程序的连接。
  2、TWordDocument对象。对应于Word文档,主要用来实现创建、销毁一个Word文档,文档的连接和断开,文档中的字符匹配查询,拼写和语法检查以及文档打印等功能。
  3、TWordFont对象。对应于Word的字体对象,用来设置Word文档中的字体属性。
  4、TWordParagraphFormat对象。对应于Word的段落对象,用来设置文档中的段落格式。

【二】启动Word程序
//建立与Word应用程序的连接  
try
Word:=TWordApplication.Create(nil); //必加此句,否则WORD.Quit后无法再启用
//提示:“RPC服务器不可用”。
word.Connect;
except
Application.MessageBox('无法连接Word。'+#13#10#13#10
+'请确认已正确安装了Word,并关闭了Word中的对话框!','提醒:',Mb_Ok+
MB_ICONSTOP);
Exit;
end;
  说明:不要“Word:=TWordApplication.Create(nil); ”也可建立与Word应用程序的连接,启动Word应用程序,但

如果用Word.Quit或Word.Destroy退出或注销Word后,便无法再次与Word建立连接,提示“RPC 服务器不可用”。添加

此句后,便可随心所欲地启动、退出Word应用程序。

【三】创建Word文件
新建空白文档的函数原型:
{//===========================================================================
Word.Documents.Add(var Template: OleVariant; var NewTemplate: OleVariant;
var DocumentType: OleVariant; var Visible: OleVariant): WordDocument;
============================================================================//}
由于在程序中需要多次调用Add函数,而函数中又不能直接使用变量的值,必须通过OleVariant型的变量名进行传递,

为避免繁琐的变量定义和赋值,我将其简化为AddDoc过程:
//WordApplication建立空白文档过程
procedure AddDoc(word:TWordApplication;Dot:String;NewDot,DocVisible:Boolean); //打开文件
var
Template,NewTemplate,DocumentType,Visible: OleVariant;
begin
Template:=Dot; //使用模板的名称,
NewTemplate:=NewDot; //新建文档的类型,True表示为模板,False表示为文档
DocumentType:=EmptyParam; //文档类型,默认为空白文档
Visible:=DocVisible; //打捞的窗口是否可见
Word.Documents.Add(Template,NewTemplate,DocumentType,Visible);
end;

【四】打开Word文件
打开文件的函数原型:
{//===========================================================================
Word.Documents.Open(var FileName: OleVariant; var ConfirmConversions: OleVariant;
var ReadOnly: OleVariant; var AddToRecentFiles: OleVariant;
var PasswordDocument: OleVariant; var PasswordTemplate: OleVariant;
var Revert: OleVariant; var WritePasswordDocument: OleVariant;
var WritePasswordTemplate: OleVariant; var Format: OleVariant;
var Encoding: OleVariant; var Visible: OleVariant; var OpenAndRepair: OleVariant;
var DocumentDirection: OleVariant; var NoEncodingDialog: OleVariant): WordDocument;
============================================================================//}
由于在程序中需要多次调用Open函数,我将其简化只有2个参数的OpenDoc过程:
//WordApplication打开文件过程
procedure OpenDoc(word:TWordApplication;sFileName:string);
var
//打开文件的参数
FileName,CfCversions,ReadOnly,AddToRctFiles,PswDocument,PswTemplate,Revert,
WPswDocument,WPswTemplate,Format,Encoding,Visible,OpenAndRepair,
DocumentDirection,NoEncodingDialog:OleVariant;
begin
// ===== 创建对象 =====
try
Word:=TWordApplication.Create(nil);
word.Connect;
except
Application.MessageBox('本机可能没有正确安装WORD!','提醒:',Mb_Ok+MB_ICONSTOP);
Exit;
end;
// ===== 打开文件 =====
Word.Visible := false;
FileName:=sFileName;
CfCversions := false;
ReadOnly:=False;
AddToRctFiles:= false;
PswDocument:= '';
PswTemplate:= '';
Revert:=true;
WPswDocument:= '';//文档密码
WPswTemplate:= '';//模板密码
Format:= EmptyParam;
Encoding:= '';
Visible:=False;
OpenAndRepair:= EmptyParam;
DocumentDirection:= EmptyParam;
NoEncodingDialog:= EmptyParam;
Word.Documents.open(FileName,CfCversions,ReadOnly,AddToRctFiles,PswDocument,
PswTemplate,Revert,WPswDocument,WPswTemplate,Format,Encoding,Visible,
OpenAndRepair,DocumentDirection,NoEncodingDialog);
end;

【五】连接Word文件
将新建的或打开的word文档通过TWordDocument对象的ConnectTo方法与TWordapplication实例建立关联。
var
DocInx: OleVariant;
begin
DocInx:=1;
// Document1.ConnectTo(Word.ActiveDocument);
Document1.ConnectTo(Word.Documents.Item(DocInx));
end;

【六】保存Word文件
Word保存文件过程的原型:
{//===========================================================================
Word.ActiveDocument.SaveAs(var FileName: OleVariant; var FileFormat: OleVariant;
var LockComments: OleVariant; var Password: OleVariant;
var AddToRecentFiles: OleVariant; var WritePassword: OleVariant;
var ReadOnlyRecommended: OleVariant; var EmbedTrueTypeFonts: OleVariant;
var SaveNativePictureFormat: OleVariant; var SaveFormsData: OleVariant;
var SaveAsAOCELetter: OleVariant; var Encoding: OleVariant;
var InsertLineBreaks: OleVariant; var AllowSubstitutions: OleVariant;
var LineEnding: OleVariant; var AddBiDiMarks: OleVariant);
safecall;
============================================================================//}
为避免繁琐地使用保存文件过程,精简为:
//WordApplication保存文件过程
procedure SaveDoc(word:TWordApplication;sFileName:string);
var
//保存文件的参数
FileName,FileFormat,LockComments,Password,AddToRecentFiles,
WritePassword, ReadOnlyRecommended,EmbedTrueTypeFonts,SaveNativePictureFormat,
SaveFormsData,SaveAsAOCELetter,Encoding,InsertLineBreaks,AllowSubstitutions,
LineEnding,AddBiDiMarks: OleVariant;
begin
FileName:=sFileName;
FileFormat:= EmptyParam;
LockComments:= EmptyParam;
Password:= EmptyParam;
AddToRecentFiles:= EmptyParam;
WritePassword:= EmptyParam;
ReadOnlyRecommended:= EmptyParam;
EmbedTrueTypeFonts:= EmptyParam;
SaveNativePictureFormat:= EmptyParam;
SaveFormsData:= EmptyParam;
SaveAsAOCELetter:= EmptyParam;
Encoding:= EmptyParam;
InsertLineBreaks:= EmptyParam;
AllowSubstitutions:= EmptyParam;
LineEnding:= EmptyParam;
AddBiDiMarks:= EmptyParam;
Word.ActiveDocument.SaveAs(FileName,FileFormat,LockComments,Password,
AddToRecentFiles,WritePassword,ReadOnlyRecommended,EmbedTrueTypeFonts,
SaveNativePictureFormat, SaveFormsData,SaveAsAOCELetter,Encoding,
InsertLineBreaks,AllowSubstitutions,LineEnding,AddBiDiMarks);
end;
如果通过TWordDocument对象保存文件,则比较简单:
Document1.SaveAs(newFileName);

【七】插入Word文件
Word插入文件过程的原型:
{//===========================================================================
InsertFile(const FileName: WideString; var Range: OleVariant;
var ConfirmConversions: OleVariant; var Link: OleVariant;
var Attachment: OleVariant); safecall;
============================================================================//}
//向打开的Word文件中插入外部文件
var i:Integer;
myRange,CfCversions,Link,Attachment: OleVariant;
s:WideString;
begin
for i :=0 to List.Items.Count-1 do
begin
myRange:=EmptyParam;
CfCversions:=EmptyParam;
Link:=EmptyParam;
Attachment:=EmptyParam;
myType:=wdPageBreak;
if (chk_AddNewPage.Checked) and (i>0) then Word.Selection.InsertBreak(myType);
s:=List.Items[i];
Word.Selection.InsertFile(s,myRange,CfCversions,Link,Attachment);
end;
end;
如果在插入文件时,要另起一页,则可在插入文件前执行:
//var myType:OleVariant;
myType:=wdPageBreak;
Word.Selection.InsertBreak(myType);
插入“分隔符”的类型定义如下:
const
wdSectionBreakNextPage = $00000002;
wdSectionBreakContinuous = $00000003;
wdSectionBreakEvenPage = $00000004;
wdSectionBreakOddPage = $00000005;
wdLineBreak = $00000006;
wdPageBreak = $00000007;
wdColumnBreak = $00000008;
wdLineBreakClearLeft = $00000009;
wdLineBreakClearRight = $0000000A;
wdTextWrappingBreak = $0000000B;
如果要插入字符串,可以使用如下方法:
Document1.Characters.Last.Select;//选择最后字符
Document1.Range.InseflAfter('要输入的文字'+#13);

【八】关闭Word文件
//关闭打开的Word文件
{//===========================================================================
procedure Close(var SaveChanges: OleVariant; var OriginalFormat: OleVariant;
var RouteDocument: OleVariant); safecall;
============================================================================//}
var
SaveChanges,OriginalFormat,RouteDocument: OleVariant;
begin
Document1.Disconnect;
Document1.Close;
SaveChanges:=False;
OriginalFormat:=EmptyParam;
RouteDocument:=EmptyParam;
Word.Documents.Close(SaveChanges,OriginalFormat,RouteDocument);
end;

【九】退出Word程序
//退出Word
begin
Word.Disconnect;
// Word.Destroy;
WORD.Quit;
end;

【十】其他相关操作
var
WORDAPP:Twordapplication;
WORDdocument:TWordDocument;
itemindex:OleVariant;
template,newtemplate,documenttype,visible:olevariant;
curr_range:Range;
row,col:Integer;
direction:OleVariant;
defaulttablebehvior,autofitbehvior:OleVariant;
curr_table:Table;
myrange:OleVariant;
savefile:OleVariant;
begin
try
try
WORDAPP:=TWordApplication.Create(nil);
WORDdocument:=TWordDocument.Create(nil);
except
ShowMessage('本机可能没有装WORD!');
Exit;
end;
itemindex:=1;
WORDAPP.Connect;
WORDAPP.Visible:=true;
WORDAPP.Documents.AddOld(EmptyParam,EmptyParam) ;
WORDdocument.ConnectTo(WORDAPP.Documents.Item(itemindex) as _document);
//关闭拼写检查,因为这会浪费较多时间
WORDAPP.Options.CheckSpellingAsYouType:= False;
WORDAPP.Options.CheckGrammarAsYouType:= False;
//页面设置
with WORDdocument.PageSetup do
begin
PaperSize:=wdPaperA4; //wdPaperA4 = $00000007;;
LeftMargin:= WORDAPP.CentimetersToPoints(2.0);
RightMargin:= WORDAPP.CentimetersToPoints(2.0);
TopMargin:= WORDAPP.CentimetersToPoints(2.0);
BottomMargin:=WORDAPP.CentimetersToPoints(2.0);
Orientation:= wdOrientLandscape; //横向打印
//centerHorizontally:= True; //水平对齐方式

end;
//写标题
curr_range:= WORDdocument.Range;
curr_range.InsertAfter('插入标题文字'+#13#10);
curr_range.Font.Size:=14;
curr_range.Bold:=1;
curr_range.ParagraphFormat.Alignment:=wdAlignPageNumberCenter; //居中对齐
//加入表格
direction:=wdCollapseEnd; //定位到标题的下一行加入表格
curr_range.Collapse(direction);
defaulttablebehvior:=wdWord10ListBehavior; //画边框线
autofitbehvior:=wdAutoFitWindow;
col:=DBGridEh1.DataSource.DataSet.FieldCount-1; //列数
row:=DBGridEh1.DataSource.DataSet.RecordCount+1; //行数
//下面两种方式也能通过
//myrange:=WORDdocument.Content.End_-1; //定位到标题的下一行加入表格
//curr_table:=WORDdocument.Tables.AddOld(WORDdocument.Range(myrange),row,col);
curr_table:=WORDdocument.Tables.Add(curr_range,row,col,defaulttablebehvior,autofitbehvior);
//WORDdocument.Tables.AddOld(curr_range,row,col);
curr_table.Range.Paragraphs.Alignment:= wdAlignParagraphLeft; //对齐方式左对齐
//写字段名及值
with DBGridEh1.DataSource.DataSet do
begin
for col:=1 to FieldCount-1 do //写字段名
begin
curr_table.Cell(1,col).Range.Font.Name:='宋体';
curr_table.Cell(1,col).Range.Font.Size:=12;
curr_table.Cell(1,col).Range.Font.Bold:=Integer(False);
if col=1 then curr_table.Cell(1,col).Range.Text:='序号'
else curr_table.Cell(1,col).Range.Text:=Fields[col-1].FieldName;
//curr_table.Columns.AutoFit;
end;
row:=2;
First;
while not Eof do //写值 
begin
for col:=1 to FieldCount-1 do
begin
if col=1 then curr_table.Cell(row,col).Range.Text:=IntToStr(row-1)
else
begin
if ( Fields[COL-1].FieldName='开始时间' ) or ( Fields[COL-1].FieldName='终止时间' ) then
curr_table.Cell(row,col).Range.Text:=FormatDateTime('yyyy-MM-dd',Fields[COL-

1].AsDateTime)
else curr_table.Cell(row,col).Range.Text:=Fields[COL-1].AsString;
end;
curr_table.Cell(row,col).Range.Font.Size:=11;
curr_table.Cell(row,col).Range.Font.Name:='宋体';
curr_table.Cell(row,col).Range.Font.Bold:=Integer(False);
end;
inc(row);
Next;
end;
curr_table.Columns.AutoFit;
end;
finally
if Trim(savefilename)<>'' then
begin
savefile:=savefilename+'.doc';
WORDdocument.SaveAs(savefile);
end;
WORDdocument.Disconnect;
WORDAPP.Disconnect;
FreeAndNil(WORDdocument);
FreeAndNil(WORDAPP);
end;
end;

你可能想看:

有话要说...

取消
扫码支持 支付码