如何利用VBA编写控制Word域的功能.docx
《如何利用VBA编写控制Word域的功能.docx》由会员分享,可在线阅读,更多相关《如何利用VBA编写控制Word域的功能.docx(36页珍藏版)》请在冰豆网上搜索。
如何利用VBA编写控制Word域的功能
表1:
工程
工程名称
设计阶段
工程检索号
卷册号
项目名称
新制
字数
图片数
建模工具
学习〔2
fw-jm-2002
软件工程专家网
60
1000
3
表2:
校核
序号
校核主要问题
执行情况
1
排列不齐
No
2
文字错
Yes
3
文字错
Yes
4
文字错
No
5
文字错
Yes
6
文字错
No
表2:
注册网址
Word域在软件开发中的应用
liyu
摘要域是Word最具有实用价值的功能之一,它表示文档中可能发生变化的数据或邮件合并文档中套用信函、标签中的占位符。
MicrosoftWord可以在您使用一些特定命令时插入域,如"插入"菜单上的"日期和时间"命令。
您也可使用"插入"菜单上的"域"命令手动插入域。
1.引言
事实上,我们在日常工作中常会脱离MicrosoftWord的操作环境。
一般,用户是先建立好一些Word文件模板,然后利用所提供的应用程序功能向Word文件模板中插入域,然后用该域对应的值取代域值,这样就达到了向MicrosoftWord文件中插入数据的作用。
我们常把数据放入数据库中,数据库的内容不断地变化,我们的域值也跟着不断地变化,取到灵活自动更新的作用,要达到这方面的功能,就应该把数据库与Word域结合起来。
首先要解决这一问题,我们必须先了解Word域有关的知识:
Word域代码位于花括号或大括号<{}>中,域类似于MicrosoftExcel中的公式:
域代码类似于公式,域结果〔域结果:
当MicrosoftWord执行域指令时,在文档中插入的文字或图形。
在打印文档或隐藏域代码时,将以域结果替换域代码。
类似于公式产生的值。
可在文档中切换显示域代码及其结果。
正好,数据库的字段名对应域代码,字段值对应域结果。
2.实现功能
下面是本人利用VBA编写的一通用的处理Word域的程序:
主要功能:
通用VB6编写通用的类,给用户提供可视化的编辑界面,用于用户在Word文件中插入域标志。
针对Word文件或Excel表格文件,扫描整个文件,将其中的域标志〔如Set"aaa"取出来,然后通过从数据库中取出"aaa"字段所对应的值,将值填写到文件中域对应的位置。
若对应位置已有值,则判断该值与要填写的值是否相同,若不同则替换。
插入值分为:
A.单纯的值,直接使用一个值替换域。
B.表格中的单元格。
若该表格填写不下,是否增加表格单元?
以及与该单元关联的域等。
3.操作步骤
3.1建立项目
开发方法:
启动VB6,新建一ActiveXDll工程,把工程名更改为VbaWord,把类名Class1更改为CSetDocField,向工程中增加一窗体Form1,窗体标题为处理Word文档,在Form1上加入2个CommandButton,用于打开文件和保存文件用的命令按钮;2个ComboBox,用于所插入的字段名;2个Label;2个CommonDialog,用于执行打开文件和保存文件。
界面如下:
3.2在项目中加入引用
按工程--引用--MicrosoftWord10.0ObjectLibrary引用Word。
3.3增加操作窗体
在Form1的代码窗中定义以下变量:
OptionBase0
'申请Word应该对象及文档对象
PrivatewdAppAsNewWord.Application<>
PrivatewdDocAsNewWord.Document<>
'所处理的Word模板
PrivateFileNameAsString
'申请CSetDocField对象
PrivatemDocFldAsNewCSetDocField<>
'Word工具栏对象及菜单栏对象
DimCommandBarIndex<>AsInteger
DimSaveCommandBarMenuIndex<>AsInteger
'在Form的Load的事件中定义的打开和保存文件的格式,并填充ComboBox数据。
ComboBox数据对应数据库表的字段名,这里由CSetDocField的属性提供。
PrivateSubForm_Load<>
DimiAsInteger
CommonDialog1.DialogTitle="打开"
CommonDialog1.Filter="Word文档<*.doc>|*.doc|Word文档模板<*.dot>|*.dot"
CommonDialog2.DialogTitle="保存文件"
CommonDialog2.Filter=Word文档<*.doc>|*.doc|Word文档模板<*.dot>|*.dot"
FieldCount=0
Me.ScaleY=vbTwips,toscale:
=vbPoints>
Fori=1TogFieldColl.Count
Combo1.AddItem>
Next
Fori=1TogTableColl.Count
Combo2.AddItem>
Next
EndSub
在Form1的代码窗中定义以下过程和函数:
'定义打开Word文件的过程。
建立Word应该对象及文档对象,并打开文件。
PrivateSubOpenWordDocument
wdApp=CreateObject<"Word.Application">
wdApp.Documents.Open
wdDoc=wdApp.ActiveDocument
wdDoc.ActiveWindow.DocumentMap=False
wdApp.Visible=True
IsWordRunning=True
EndSub
'在文档中插入域.KeyWord:
域的关键字.
这里我们利用Word文档对象的域对象的Add方法向Word文件中插入域。
域的Data属性代表该域的名称。
插入域时应该选取得插入点,既用户光标处位置。
如果该位置是单元格且已插入域应该提示是否覆盖
PrivateFunctionInsertFieldAsInteger
DimmySelectionAsSelection
DimCodeAsString
DimMyFieldAsField
DimmyRangeAsRange
wdApp.Selection.Collapse=wdCollapseEnd>
mySelection=wdApp.Selection'插入点
IfIsCell=TrueThen
IfCellFieldCount>0Then
IfMsgBox<"该单元格已有域,是否覆盖?
",vbYesNo>=6Then
mySelection.Cells<1>.Select<>
mySelection.Delete<>'.Text=Value
'mySelection.DeleteUnit:
=wdCharacter,Count:
=1
'mySelection.Cells<1>.Range.Fields<1>.Delete
Else
ExitFunction
EndIf
EndIf
EndIf
MyField=wdDoc.Fields.Add=mySelection.Range,Type:
=wdFieldAddin>
MyField.Data=KeyWord
EndFunction
'选择点<光标>是否是单元格.
我们可以通过选择点的表格数判断插入点的性质。
表格数为0,则选择点不位于单元格中,反则不位于单元格中。
PrivateFunctionIsCellAsBoolean
IfmySelection.Tables.Count>0Then
IsCell=True
Else
IsCell=False
EndIf
EndFunction
'取得选择点<光标>的单元格的域数
PrivateFunctionCellFieldCountAsInteger
EndFunction
'打开Word文件.并使处理界面位于Word最顶端,适当调整Word位置,关闭Word其它功能。
PrivateSubcmdOpenFile_Click<>
CommonDialog1.ShowOpen<>
FileName=CommonDialog1.FileName
IfFileName=""Then
ExitSub
EndIf
OpenWordDocument
IsShowField
SetWordSize<0,42,2000,2000>
CloseCommandBar<>
Me.top=0
Me.Left=0
Me.width=100000
Me.height=850
Picture1.top=Me.top
Picture1.Left=Me.Left+2000
cmdSave.Left=2000
cmdSave.top=cmdOpenFile.top
Combo1.Enabled=True
Combo2.Enabled=True
cmdSave.Visible=True
cmdOpenFile.Visible=False
EndSub
'保存Word文件.
PrivateSubcmdSave_Click<>
IsShowField
CommonDialog2.FileName=gSavePath+FileName
CommonDialog2.FileName=gSavePath+FileName
CommonDialog2.ShowSave<>
wdDoc.SaveAs
EndSub
'用户选择所插入域的域名,并在光标处插入域。
PrivateSubCombo1_Click<>
DimKeyWordAsString
KeyWord=Combo1.Text
InsertField
EndSub
'用户选择所插入域的域名,并在光标处插入域。
域所对应多值时,域只能插入表格中。
且要与单值域区分,标记为多值插入。
PrivateSubCombo2_Click<>
DimKeyWordAsString
mySelection=wdApp.Selection'插入点
IfIsCell<>TrueThen
MsgBox<"该位置不是单元格,请选择单元格",vbOKOnly+vbExclamation>
ExitSub
EndIf
KeyWord=Combo2.Text+"F"'标记是多值
InsertField
EndSub
PrivateSubForm_Load<>
DimiAsInteger
CommonDialog1.DialogTitle="打开"
CommonDialog1.Filter="Word文档<*.doc>|*.doc|Word文档模板<*.dot>|*.dot"
CommonDialog2.DialogTitle="保存文件"
CommonDialog2.Filter="Word文档<*.doc>|*.doc|Word文档模板<*.dot>|*.dot"
FieldCount=0
Me.ScaleY=vbTwips,toscale:
=vbPoints>
Fori=1TogFieldColl.Count
Combo1.AddItem>
Next
Fori=1TogTableColl.Count
Combo2.AddItem>
Next
EndSub
'**********************************************************
PrivateFunctionInsertFieldByKeyWordAsInteger
DimIDAsInteger
FieldCount=FieldCount+1
ReDimMyField
ID=InsertField
MyField.ID=ID
MyField.KeyWord=KeyWord
EndFunction
PrivateSubSetEnabled
DimobjAsControl
ForEachobjInMe.Controls
IfTypeName="TextBox"Then
obj.Enabled=isEnabled
EndIf
IfTypeName="ComboBox"Then
obj.Enabled=isEnabled
EndIf
IfTypeName="CheckBox"Then
obj.Enabled=isEnabled
EndIf
IfTypeName="CommandButton"Then
obj.Enabled=isEnabled
EndIf
Next
EndSub
'在关闭该界面时应该恢复Word环境。
PrivateSubForm_Unload
IfFileName<>""Then
OpenCommandBar<>
wdApp.ActiveWindow.Close<>
wdApp.Quit<>
EndIf
EndSub
'定义Word环境的大小。
PrivateSubSetWordSize
wdApp.WindowState=wdWindowStateNormal
wdApp.Left=Left
wdApp.top=top
wdApp.width=width
wdApp.height=height
EndSub
'定义Word域代码是否可显示。
PrivateSubIsShowField
wdApp.ActiveWindow.View.ShowFieldCodes=IsShow
EndSub
'关闭Word环境的所有命令及菜单。
PrivateSubCloseCommandBar<>
DimiAsInteger
DimcBar
ReDimCommandBarIndex<1>
ReDimSaveCommandBarMenuIndex<1>
i=0
ForEachcBarInwdDoc.CommandBars
IfcBar.Type=0AndcBar.Enabled=TrueThen
IfcBar.Visible=TrueThen
ReDimCommandBarIndex
CommandBarIndex=cBar.Index
i=i+1
cBar.Visible=False
EndIf
EndIf
Next
i=0
ForEachcBarInwdDoc.CommandBars<"MenuBar">.Controls
IfcBar.Visible=TrueThen
ReDimSaveCommandBarMenuIndex
SaveCommandBarMenuIndex=cBar.Index
i=i+1
cBar.Visible=False
EndIf
Next
EndSub
'恢复Word环境的所有命令及菜单。
PrivateSubOpenCommandBar<>
DimiAsInteger
Fori=0ToUBound-1
wdDoc.CommandBars.Visible=True
Next
Fori=0ToUBound-1
CommandBars<"MenuBar">.Controls.Visible=True
Next
EndSub
3.2增加窗体
下面我们继续编写CSetDocField类的内容。
CSetDocField类应该提供单值域和多值的域名,所以我们把它们定义为CSetDocField类的属性,并提供一运行上面窗口的方法。
这里我们要利用一些技巧,在定义类并向类属性赋性值后,事实赋性值是保存在所定义的实类中,该实类一旦消失,值也随着消失。
如何不通过该实类取得类的属性?
这是困扰许多开发人员的问题。
我的解决方法是申请与类属性对应的全局变量。
向类属性的同时,把值保存在对应的全局变量中,取值时取出对应的全局变量的值就可。
这里我们选增加一Module,其Code如下:
PublicgSavePathAsString
PublicgFieldCollAsCollection
PublicgTableCollAsCollection
SubMain<>
Form1.Show<1>
EndSub
下面我利用全局变量当作类属性使用的技巧:
CSetDocField类的Code:
PublicSubRun<>
StaticFieldCollAsCollection
StaticTableCollAsCollection
Main<>
EndSub
PropertyGetFieldColl<>AsCollection
'SetFieldColl=mFieldColl
SetFieldColl=gFieldColl
EndProperty
PropertyLetFieldColl
SetgFieldColl=Field
EndProperty
PropertyGetTableColl<>AsCollection
SetTableColl=gTableColl
EndProperty
PropertyLetTableColl
SetgTableColl=Field
EndProperty
PropertyLetSavePath
gSavePath=str
EndProperty
这里,我们把插入域的类编写好了,只要在VB6的文件菜单中执行生成该类的文件就可生成DLL文件。
下面编写将值填写到文件中域对应的位置的类。
在VbaWord工程中增加新类CWriteDataToDocument。
类CWriteDataToDocument由调用者提供所处理的文件模板,所以它应该有一文档属性DocumentName,打开DocumentName文件,向DocumentName文件中插入单值和多值。
插入多值时要判断是否增加单元格。
如果对应的值多于所提供的表格行数,则要增加行。
下面是它的完整Code:
PrivatewdAppAsNewWord.Application<>
PrivatewdDocAsNewWord.Document<>
PrivateIsInsertRowAsBoolean'是否已经插入了行
PublicDocumentNameAsString
PublicFunctionFillData<>
OpenWordDocument<>
InsertValue<>
InsertCollection<>
wdDoc.SaveAs
EndFunction
PublicFunctionGetValueByFieldAsString
GetValueByField="liyu"
EndFunction
PublicFunctionGetRecordSetByFieldAsCollection
DimcollAsNewCollection<>
coll.Add<"li">
coll.Add<"yu">
GetRecordSetByField=coll
EndFunction
PrivateSubOpenWordDocument<>
wdApp=CreateObject<"Word.Application">
wdApp.Documents.Open
wdDoc=wdApp.ActiveDocument
wdApp.Visible=True
'wdDoc.Ac