如何利用VBA编写控制Word域的功能

Word 域在软件开发中的应用liyu摘要 域是Word 最具有实用价值的功能之一, 它表示文档中可能发生变化的数据或邮件合并文档中套用信函、标签中的占位符。Microsoft Word 可以在您使用

Word 域在软件开发中的应用

liyu

摘要 域是Word 最具有实用价值的功能之一, 它表示文档中可能发生变化的数据或邮件合并文档中套用信函、标签中的占位符。Microsoft Word 可以在您使用一些特定命令时插入域,如“插入”菜单上的“日期和时间”命令。您也可使用“插入”菜单上的“域”命令手动插入域。

1. 引言

事实上,我们在日常工作中常会脱离Microsoft Word 的操作环境。一般,用户是先建立好一些Word 文件模板,然后利用所提供的应用程序功能向Word 文件模板中插入域,然后用该域对应的值取代域值,这样就达到了向Microsoft Word 文件中插入数据的作用。我们常把数据放入数据库中,数据库的内容不断地变化,我们的域值也跟着不断地变化,取到灵活自动更新的作用,要达到这方面的功能,就应该把数据库与Word 域结合起来。

首先要解决这一问题,我们必须先了解Word 域有关的知识:Word 域代码位于花括号或大括号 ( { } ) 中,域类似于 Microsoft Excel 中的公式:域代码类似于公式,域结果(域结果:当 Microsoft Word 执行域指令时,在文档中插入的文字或图形。在打印文档或隐藏域代码时,将以域结果替换域代码。)类似于公式产生的值。可在文档中切换显示域代码及其结果。正好,数据库的字段名对应域代码,字段值对应域结果。

,

2. 实现功能

下面是本人利用VBA 编写的一通用的处理Word 域的程序:

主要功能:通用VB6编写通用的类,给用户提供可视化的编辑界面,用于用户在Word 文件中插入域标志。针对Word 文件或Excel 表格文件,扫描整个文件,将其中的域标志(如Set “aaa ”)取出来,然后通过从数据库中取出”aaa ”字段所对应的值,将值填写到文件中域对应的位置。若对应位置已有值,则判断该值与要填写的值是否相同,若不同则替换。插入值分为:

A. 单纯的值,直接使用一个值替换域。

B. 表格中的单元格。若该表格填写不下,是否增加表格单元?以及与该单元关联的域等。

3. 操作步骤

3.1建立项目

开发方法:启动VB6,新建一ActiveX Dll 工程,把工程名更改为VbaWord ,把类名Class1更改为CSetDocField ,向工程中增加一窗体Form1, 窗体标题为处理Word 文档,在Form1上加入2个CommandButton ,用于打开文件和保存文件用的命令按钮;2个ComboBox ,用于所插入的字段名;2个 Label;2个CommonDialog ,用于执行打开文件和保存文件。界面如下:

3.2在项目中加入引用

按工程--引用--Microsoft Word 10.0 Object Library引用Word(OFFICE 2000为Microsoft Word 9.0 Object Library)。

3.3增加操作窗体

在Form1的代码窗中定义以下变量:

Option Base 0

' 申请Word 应该对象及文档对象

Private wdApp As New Word.Application()

Private wdDoc As New Word.Document()

' 所处理的Word 模板

Private FileName As String

' 申请CSetDocField 对象

,

Private mDocFld As New CSetDocField()

'Word 工具栏对象及菜单栏对象

Dim CommandBarIndex() As Integer

Dim SaveCommandBarMenuIndex() As Integer

' 在Form 的Load 的事件中定义的打开和保存文件的格式,并填充ComboBox 数据。ComboBox 数据对应数据库表的字段名,这里由CSetDocField 的属性提供。

Private Sub Form_Load()

Dim i As Integer

CommonDialog1.DialogTitle = "打开"

CommonDialog1.Filter = "Word文档(*.doc)|*.doc|Word文档模板(*.dot)|*.dot"

CommonDialog2.DialogTitle = "保存文件"

CommonDialog2.Filter = Word文档(*.doc)|*.doc|Word文档模板(*.dot)|*.dot" FieldCount = 0

Me.ScaleY(Me.height, fromscale:=vbTwips, toscale:=vbPoints)

For i = 1 To gFieldColl.Count

Combo1.AddItem(gFieldColl.Item(i))

Next

For i = 1 To gTableColl.Count

Combo2.AddItem(gTableColl.Item(i))

Next

End Sub

在Form1的代码窗中定义以下过程和函数:

' 定义打开Word 文件的过程。建立Word 应该对象及文档对象, 并打开文件。

Private Sub OpenWordDocument(ByVal FileName As String)

wdApp = CreateObject("Word.Application")

wdApp.Documents.Open(FileName)

wdDoc = wdApp.ActiveDocument

wdDoc.ActiveWindow.DocumentMap = False

wdApp.Visible = True

IsWordRunning = True

End Sub

' 在文档中插入域.KeyWord:域的关键字.

这里我们利用Word 文档对象的域对象的Add 方法向Word 文件中插入域。域的Data 属性代表该域的名称。插入域时应该选取得插入点(Selection),既用户光标处位置。如果该位置是单

,

元格且已插入域应该提示是否覆盖

Private Function InsertField(ByVal KeyWord As String) As Integer

Dim mySelection As Selection

Dim Code As String

Dim MyField As Field

Dim myRange As Range

wdApp.Selection.Collapse(Direction:=wdCollapseEnd)

mySelection = wdApp.Selection '插入点

If IsCell(mySelection) = True Then

If CellFieldCount(mySelection) > 0 Then

If MsgBox("该单元格已有域, 是否覆盖?", vbYesNo) = 6 Then

mySelection.Cells(1).Select()

mySelection.Delete() ' .Text = Value

' mySelection.Delete Unit:=wdCharacter, Count:=1

'mySelection.Cells(1).Range.Fields(1).Delete

Else

Exit Function

End If

End If

End If

MyField = wdDoc.Fields.Add(Range:=mySelection.Range, Type:=wdFieldAddin) MyField.Data = KeyWord

End Function

' 选择点(光标) 是否是单元格.

我们可以通过选择点的表格数判断插入点的性质。表格数为0,则选择点不位于单元格中,反则不位于单元格中。

Private Function IsCell(ByVal mySelection As Selection) As Boolean

If mySelection.Tables.Count > 0 Then

IsCell = True

Else

IsCell = False

End If

End Function

' 取得选择点(光标) 的单元格的域数

Private Function CellFieldCount(ByVal mySelection As Selection) As Integer CellFieldCount = mySelection.Cells(1).Range.Fields.Count

End Function

' 打开Word 文件. 并使处理界面位于Word 最顶端,适当调整Word 位置,关闭Word 其它功能。 Private Sub cmdOpenFile_Click()

,

CommonDialog1.ShowOpen()

FileName = CommonDialog1.FileName

If FileName = "" Then

Exit Sub

End If

OpenWordDocument(FileName)

IsShowField(True)

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

End Sub

' 保存Word 文件.

Private Sub cmdSave_Click()

IsShowField(False)

CommonDialog2.FileName = gSavePath FileName CommonDialog2.FileName = gSavePath FileName CommonDialog2.ShowSave()

wdDoc.SaveAs(CommonDialog2.FileName) End Sub

' 用户选择所插入域的域名,并在光标处插入域。 Private Sub Combo1_Click()

Dim KeyWord As String

KeyWord = Combo1.Text

InsertField(KeyWord)

End Sub

,

' 用户选择所插入域的域名,并在光标处插入域。

域所对应多值时,域只能插入表格中。且要与单值域区分,标记为多值插入。

Private Sub Combo2_Click()

Dim KeyWord As String

mySelection = wdApp.Selection '插入点

If IsCell(mySelection) <> True Then

MsgBox("该位置不是单元格, 请选择单元格", vbOKOnly vbExclamation) Exit Sub

End If

KeyWord = Combo2.Text "F" '标记是多值

InsertField(KeyWord)

End Sub

Private Sub Form_Load()

Dim i As Integer

CommonDialog1.DialogTitle = "打开"

CommonDialog1.Filter = "Word文档(*.doc)|*.doc|Word文档模板(*.dot)|*.dot"

CommonDialog2.DialogTitle = "保存文件"

CommonDialog2.Filter = "Word文档(*.doc)|*.doc|Word文档模板(*.dot)|*.dot" FieldCount = 0

Me.ScaleY(Me.height, fromscale:=vbTwips, toscale:=vbPoints)

For i = 1 To gFieldColl.Count

Combo1.AddItem(gFieldColl.Item(i))

Next

For i = 1 To gTableColl.Count

Combo2.AddItem(gTableColl.Item(i))

Next

End Sub

'**********************************************************

Private Function InsertFieldByKeyWord(ByVal KeyWord As String) As Integer Dim ID As Integer

FieldCount = FieldCount 1

ReDim MyField(FieldCount)

ID = InsertField(KeyWord)

,

MyField(FieldCount).ID = ID

MyField(FieldCount).KeyWord = KeyWord

End Function

Private Sub SetEnabled(ByVal isEnabled As Boolean)

Dim obj As Control

For Each obj In Me.Controls

If TypeName(obj) = "TextBox" Then

obj.Enabled = isEnabled

End If

If TypeName(obj) = "ComboBox" Then

obj.Enabled = isEnabled

End If

If TypeName(obj) = "CheckBox" Then

obj.Enabled = isEnabled

End If

If TypeName(obj) = "CommandButton" Then

obj.Enabled = isEnabled

End If

Next

End Sub

' 在关闭该界面时应该恢复Word 环境。

Private Sub Form_Unload(ByVal Cancel As Integer)

If FileName <> "" Then

OpenCommandBar()

wdApp.ActiveWindow.Close()

wdApp.Quit()

End If

End Sub

' 定义Word 环境的大小。

Private Sub SetWordSize(ByVal Left As Integer, ByVal top As Integer, ByVal width As Integer, ByVal height As Integer)

wdApp.WindowState = wdWindowStateNormal

wdApp.Left = Left

wdApp.top = top

wdApp.width = width

wdApp.height = height

End Sub

' 定义Word 域代码是否可显示。

,

Private Sub IsShowField(ByVal IsShow As Boolean)

wdApp.ActiveWindow.View.ShowFieldCodes = IsShow

End Sub

' 关闭Word 环境的所有命令及菜单。

Private Sub CloseCommandBar()

Dim i As Integer

Dim cBar

ReDim CommandBarIndex(1)

ReDim SaveCommandBarMenuIndex(1)

i = 0

For Each cBar In wdDoc.CommandBars

If cBar.Type = 0 And cBar.Enabled = True Then If cBar.Visible = True Then

ReDim CommandBarIndex(i 1)

CommandBarIndex(i) = cBar.Index

i = i 1

cBar.Visible = False

End If

End If

Next

i = 0

For Each cBar In wdDoc.CommandBars("Menu Bar").Controls If cBar.Visible = True Then

ReDim SaveCommandBarMenuIndex(i 1)

SaveCommandBarMenuIndex(i) = cBar.Index

i = i 1

cBar.Visible = False

End If

Next

End Sub

' 恢复Word 环境的所有命令及菜单。

Private Sub OpenCommandBar()

Dim i As Integer

For i = 0 To UBound(CommandBarIndex) - 1

wdDoc.CommandBars(i 1).Visible = True

Next

For i = 0 To UBound(SaveCommandBarMenuIndex) - 1

CommandBars("Menu Bar").Controls(i 1).Visible = True Next

End Sub

,

3.2增加窗体

下面我们继续编写CSetDocField 类的内容。

CSetDocField 类应该提供单值域和多值的域名,所以我们把它们定义为CSetDocField 类的属性,并提供一运行上面窗口的方法。这里我们要利用一些技巧,在定义类并向类属性赋性值后,事实赋性值是保存在所定义的实类中,该实类一旦消失,值也随着消失。如何不通过该实类取得类的属性?这是困扰许多开发人员的问题。我的解决方法是申请与类属性对应的全局变量。向类属性的同时,把值保存在对应的全局变量中,取值时取出对应的全局变量的值就可。

这里我们选增加一Module, 其Code 如下:

Public gSavePath As String

Public gFieldColl As Collection

Public gTableColl As Collection

Sub Main()

Form1.Show(1)

End Sub

下面我利用全局变量当作类属性使用的技巧:

CSetDocField 类的Code:

Public Sub Run()

Static FieldColl As Collection

Static TableColl As Collection

Main()

End Sub

Property Get FieldColl() As Collection

'Set FieldColl = mFieldColl

Set FieldColl = gFieldColl

End Property

Property Let FieldColl(Field As Collection)

Set gFieldColl = Field

End Property

Property Get TableColl() As Collection

Set TableColl = gTableColl

End Property

Property Let TableColl(Field As Collection)

Set gTableColl = Field

End Property

Property Let SavePath(str As String)

,

gSavePath = str

End Property

这里,我们把插入域的类编写好了,只要在VB6的文件菜单中执行生成该类的文件就可生成DLL 文件。

下面编写将值填写到文件中域对应的位置的类。

在VbaWord 工程中增加新类CWriteDataToDocument 。

类CWriteDataToDocument 由调用者提供所处理的文件模板,所以它应该有一文档属性

DocumentName ,打开DocumentName 文件,向DocumentName 文件中插入单值和多值。插入多值时要判断是否增加单元格。如果对应的值多于所提供的表格行数,则要增加行。下面是它的完整Code:

Private wdApp As New Word.Application()

Private wdDoc As New Word.Document()

Private IsInsertRow As Boolean '是否已经插入了行

Public DocumentName As String

Public Function FillData()

OpenWordDocument()

InsertValue()

InsertCollection()

wdDoc.SaveAs(DocumentName)

End Function

Public Function GetValueByField(ByVal FieldName As String) As String GetValueByField = "liyu"

End Function

Public Function GetRecordSetByField(ByVal FieldName As String) As Collection Dim coll As New Collection()

coll.Add("li")

coll.Add("yu")

GetRecordSetByField = coll

End Function

Private Sub OpenWordDocument()

wdApp = CreateObject("Word.Application")

wdApp.Documents.Open(DocumentName)

wdDoc = wdApp.ActiveDocument

wdApp.Visible = True

'wdDoc.ActiveWindow.DocumentMap = False

End Sub

标签: