Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
Bon Mot
This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.
By Cindy Meister
I think there is general agreement: The less code required to update information in a Word document, the better. Some 80-plus fields are built into Word that provide information about the file and the user; store, display, and manipulate reference information; and link the document to other applications - all without a bit of code. This series of articles will explore some interesting solutions that can be accomplished with fields, field combinations, and a small amount of code to improve user friendliness. Most of the field examples can be applied to all versions of Word, but the code samples are VBA and therefore applicable only to Word 97 or Word 2000.
A complete listing of available fields can be found in the Insert | Field dialog box (see FIGURE 1). A short description of the field's purpose is displayed there, but more in-depth information can be referenced by first clicking the ? at the top right, then the field name, in order to call up Help for that field. The Word Help files for fields contain detailed information and examples, plus links to related topics (unlike the Help for most other subjects).
FIGURE 1: The main Insert | Field dialog box.
The results of many fields can be altered or enhanced by using switches. The user can select from a list of relevant switches by clicking the Options button on the Insert | Field dialog box to open the dialog box shown in FIGURE 2. FIGURE 3 lists important switches common to many fields.
FIGURE 2: There are general, numeric, and field-specific switches that can be added to many fields to modify or enhance their behavior.
Switch |
Description |
Example |
\# |
Numeric picture. |
|
\@ |
Date picture. |
|
\* CharFormat |
Format entire field with formatting of first field character. |
|
\* Upper \* Lower \* Caps \* FirstCap |
Display field result in all upper case; all lower case; "title" case; "sentence" case. |
|
\! |
Prevent any fields included in referenced text from updating. |
|
\* alphabetic |
Displays alphabetic, rather then numeric character. |
|
\* Arabic |
Forces display of an Arabic number. |
|
\* Roman | Displays Roman numerals. |
|
\* Ordinal | Result is displayed as an ordinal number. |
|
\* Hex |
Displays the hexadecimal value. |
|
\* CardText |
The number is displayed in words (no decimals). |
|
\* DollarText |
Number in words with two decimal places. |
|
\* OrdText |
Ordinal number as text. |
|
FIGURE 3: Important, common switches.
Insert | Field is a handy tool for the average user, and for getting an overview of available fields. It's less useful, however, for accessing the full potential of fields in combination. Sometimes, you'll need to work with the field codes in the document directly. FIGURE 4 lists the keyboard shortcuts and basic VBA syntax of the most important commands.
Action |
Keystroke |
VBA syntax |
Update fields in current selection. |
[F9] |
Object.Fields.Update |
Insert field brackets. |
[Ctrl][F9] |
Object.Fields.Add Range:=RangeObject |
Toggle field code display. |
[Alt][F9] |
View.ShowFieldCodes = True/False |
Turn field code into plain text. |
[Ctrl][Shift][F9] |
Object.Fields.Unlink |
Lock field to prevent updating. |
[Ctrl][F11] |
Object.Fields.Locked = True |
Unlock field. |
[Ctrl][Shift][F11] |
Object.Fields.Locked = False |
FIGURE 4: Commands for editing fields directly in a document.
Now let's look at some of the things Word fields allow you to do.
A common task is to refer to information found in the same or another document. Using bookmarks and REF fields, existing content can be displayed in other areas of a document, rather than duplicating the text. If the content of the bookmark is edited, those changes will automatically be displayed once the REF fields are updated. REF fields are also used by Word when generating cross-references.
Less well-known are the PAGEREF and STYLEREF fields. The PAGEREF field returns the page number of the bookmark. When Word generates a Table of Contents (TOC), for example, it sets bookmarks and uses hidden PAGEREF fields to display the page numbers in the TOC. It's also the basis of a work-around for the unreliable behavior of the two fields that display the total number of pages in a document and in a section (NUMPAGES and SECTIONPAGES, respectively). Simply insert a bookmark at the end of the document or section, then put a PAGEREF field referencing that bookmark where the total number of pages should be displayed:
{ PAGE } of { PAGEREF BookmarkName \*
CharFormat}
Note that the \* CharFormat switch will force the field to display with the same formatting as applied to the first character in the field, rather than that of the bookmarked text. This is important, since the font attributes of the header or footer often differ from that of the text.
The STYLEREF field enables you to pick up the text or paragraph numbering from document content formatted with the specified style. It's most frequently used in document headers or footers to display the chapter or heading to which the current page belongs, or for dictionary-style headers that list the first and last entry in the style found on the page.
An interesting, less usual, application is to display version or title information from the title page throughout a long, multi-section document. Unlike a REF field, which depends on the presence of bookmarks (which are prone to accidental deletion) or DocProperty fields (that may be overlooked when updating a document), using a unique style to mark the information meant for a STYLEREF field to pick it up is transparent and easy for the user. To ensure that the information is included in a document, the developer must only check for the presence of the style on the title page, and that it contains a minimum number of characters.
The procedure in FIGURE 5 is a possible approach. The style name and range in which the style should be are passed to the function. The range is checked for the presence of the style using the Find property. If it's found, the number of characters in the range (which now comprises what was found) is returned. Otherwise it is zero. Error trapping is turned off for the function, because a VBA error is returned if the style isn't found in the document's collection of styles.
Function
ExistsStyle(rng As Word.Range, _
sStyleName
As String)
As Long
On
Error Resume
Next
With rng.Find
.ClearFormatting
.ClearAllFuzzyOptions
.Forward =
True
.Wrap =
wdFindStop
.Text = ""
.Style =
sStyleName
If .Execute = True
Then
ExistsStyle = Len(rng.Text)
Else
ExistsStyle = 0
End If
End With
End
Function
FIGURE 5: Ascertain whether any text in a range is formatted with a specific style.
By now it's common knowledge that Word's Master Document feature is buggy. Therefore, creating one long document is usually preferable to using the feature. If, however, a set of documents should be centrally maintained and combined as required, there are alternate approaches. RD fields, for instance, can be used to pick up information from other documents when generating tables of content and indexes.
Content from other Word documents is often best accessed using the Insert | File command (see FIGURE 6). If the Link option is activated, Word generates an INCLUDETEXT field; specifying a bookmark range in addition brings in only that part of the file contained in the bookmark. Normally, information is only displayed in a field. It can't be edited on a permanent basis, and will be lost when the field is updated. INCLUDETEXT is an exception; editing changes can be sent back to the source document by pressing [Ctrl][Shift][F7].
FIGURE 6: The Insert | Fielddialog box in Word 2000. Click the Range button to specify a bookmark name; click the arrow to the right of the Insert button to select the Insert as****Link option.
By combining INCLUDETEXT with IF fields, text can be displayed according to set criteria - often a requirement for mail merge. The following field set references a bookmark containing a dunning notice, based on the reminder number:
{ INCLUDETEXT "C:\\My
Documents\\DunningText.doc"
{ IF {MERGEFIELD ReminderNum }
= 1 "Notice1"
"{IF { MERGEFIELD ReminderNum }
= 2 "Notice2"
"Notice3" }" } }
Note that Word's IF field doesn't use argument separators; each True/False pair is marked by a pair of quotation marks separated by a space.
INCLUDETEXT can also be used to generate consecutive page numbering across multiple documents. In the first document of a pair:
- Insert a PAGE field at the end of the document.
- Select it and assign it a bookmark (PageNum, for example).
- Format it as hidden or white so it won't be visible.
In the second document of the pair:
- Create an expression field that adds the current page number in this document to the page number in the first document, referenced using an INCLUDETEXT field.
- Complete the INCLUDETEXT field with a \* CharFormat and a \* ! switch to override the hidden formatting, and prevent the PAGE field being referenced to update to the page number in the current document. For example:
{ = { PAGE } + { INCLUDETEXT
"C:\\My Documents\\Chap1.doc"
PageNum \* CharFormat \* ! }
}
Reports often include tables or charts that were created with Excel. The question of the best/easiest way to insert this information in Word often comes up. On the whole, copying the Excel data and using Paste Special to insert it in a Word document gives the best results. It allows you to control the selection exactly. You can choose to insert a table as an object, or in Word table format, and you can specify whether to set up a link.
Of course, this approach is less satisfactory if the reporting tool should be fully automated. But an examination of the Paste Special result indicates an alternate solution. Paste Special with a link inserts a LINK field, such as:
{ LINK Excel.Sheet.8
"C:\\My Documents\\Monthly
Reports\\JAN2000.XLS"
NorthRegionSales!R1C1:R11C6 \a
\r \* MERGEFORMAT }
Or, for a chart:
{ LINK Excel.Chart.8
"C:\\My Documents\\Monthly
Reports\\JAN2000.XLS"
"All Regions Sales Chart" \a \p
}
All that's needed to generate this field in VBA are the various elements in the field: the application class, the file path, and the workbook range. The optional \a switch instructs Word to automatically update the link. The switches \p and \r determine how the table information should be displayed - as a picture (OLE object), or in RichText format (as a Word table), respectively.
Include the \* MergeFormat switch when formatting applied directly in Word should override Excel formatting when the field is updated. (Please note this is broken in Word 2000.) A very simple example is demonstrated in FIGURE 7. All the field elements are determined, then combined into sFieldText. For the Add method of the Fields object, the Range (end of the document) is required. The Type of field is passed as a built-in Word constant; the Text will automatically follow the field name. PreserveFormatting instructs VBA whether to include the \* MergeFormat switch.
Sub
InsertLinkFieldForExcelData()
Dim rng As Word.Range
Dim sWBPath As
String
Dim sSheet As
String
Dim sRange As
String
Dim sAppClass As
String
Dim sFieldText As
String
' Field
will be inserted at the end of current document.
Set rng = ActiveDocument.Range
rng.Collapse
Direction:=wdCollapseEnd
' Info
required for creating LINK field.
sWBPath = _
"C:\\My
Documents\\Monthly Reports\\JAN2000.XLS"
sSheet = "NorthRegionSales"
sRange = "SalesData"
If
Instr(sSheet, "Chart") = 0 Then
sAppClass =
"Excel.Sheet.8"
sFieldText =
sAppClass & " " & """" & sWBPath & _
""""
& " " & """" & sSheet & "!" & _
sRange & """" & " \r"
Else
sAppClass =
"Excel.Chart.8"
sFieldText =
sAppClass & " " & """" & sWBPath & _
""""
& " " & """" & sSheet & """" & " \p"
End If
' Insert
the LINK field.
ActiveDocument.Fields.Add
Range:=rng, _
Type:=wdFieldLink, Text:=sFieldText, _
PreserveFormatting:=
True
' Break
the link to the Excel source.
rng.MoveEnd wdCharacter,
1
rng.Fields.Unlink
End
Sub
FIGURE 7: Include the \* MergeFormat switch when formatting applied directly in Word should override Excel formatting when the field is updated.
Sometimes the Excel data should not remain linked to its source. In this case, the field can simply be unlinked after it's been inserted, resulting in an embedded object, or - if a spreadsheet has been inserted in RichText format - a Word table.
There are definite problems maintaining auto-numbering when converting between Word 97/2000 and earlier versions, as well as with numbering in shared or exchanged Word 97/2000 documents. SEQ fields provide an alternative that's stable and reliable across all versions of WinWord. SEQ is short for "sequence" and enables you to have many independent lists in a document. Word itself uses SEQ fields to generate figure numbering sequences in captions.
The basic SEQ field is quite simple. It consists of the field name plus the sequence identifier, e.g. { SEQ HdLevel1 }. The field-specific switches, shown in FIGURE 8, provide versatility and flexibility when generating sequences.
\c |
Repeats the closest preceding sequence number. This is useful for inserting chapter numbers in headers or footers. |
\h |
Hides the field result. Use it to refer to a SEQ field in a cross-reference without printing the number. For example, you might want to refer to a numbered chapter, but not print the chapter number. The \h switch doesn't hide the field result if a Format (\*) switch is also present. |
\n |
Inserts the next sequence number for the specified items. This is the default. |
\r n |
Resets the sequence number to the specified number n. For example, { SEQ figure \r 3 } starts figure numbering at 3. |
\s |
Resets the sequence number at the heading level following the "s". For example, { SEQ figure \s 2 } starts numbering at the Heading 2 style (not available in older versions of Word.) |
FIGURE 8: SEQ field switches (from Word's Help files).
For example, a three-level, outline-numbering sequence can be created using the combinations shown in FIGURE 9. If each outline-level field combination is saved as an individual AutoText entry, the numbering can quickly be inserted by the user from keyboard assignments, or a toolbar with buttons for each outline level, or an AutoText list.
Result |
SEQ Field |
|
|
|
|
|
|
|
|
|
|
|
|
FIGURE 9: Outline numbering using SEQ fields.
One drawback of using SEQ fields is certainly the fact that the numbering will not update automatically when the order of numbered items is changed, or a new item is inserted into an existing list. Indeed, exactly what causes fields to update (and when) can be very confusing (Knowledge Base article Q89953 provides some explanation). Activating Tools | Options | Print | Update Fields should ensure that everything will be correct when the document is printed, but may not be a satisfactory solution for the user working with the document.
Programmatically, all fields in a document can be updated using a routine such as this:
Sub
UpdateAllDocFields()
Dimsry
ForEach sry
In ActiveDocument.StoryRanges
sry.Fields.Update
NextStr
End
Sub
If the document is large, however, or contains many fields - especially complex field sets or fields that force repagination - this process can be rather slow. It may therefore be advantageous to update only certain types of fields. The following procedure demonstrates how to update only SEQ fields of a HdLevel sequence:
Sub
UpdateOnlyHdLevelSEQFields()
Dim fld As Word.Field
For Each fld
In ActiveDocument.Fields
If fld.Type =
wdFieldSequence Then
If InStr(fld.Code, "HdLevel") <> 0
Then
fld.Update
End If
End If
Next fld
End
Sub
SEQ fields can also be used to generate types of numbering sequences that Word's autonumbering cannot (for example, incrementing numbering by a factor other than one, or numbering a list in reverse order). FIGURE 10 shows the field combinations for generating a sequence from 5 to 1. Set a starting number that's one higher than the number you want to count down from; then subtract the value of the SEQ sequence from that number.
{ Set StartNum 6 }
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 5
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 4
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 3
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 2
{ = { StartNum } - { SEQ RevNum1 } \#
0 } Paragraph 1
Of course, you can make it much easier for the user to create such sequences with a bit of VBA code, such as that shown in Listing One. The user selects the paragraphs to be numbered in reverse order, then starts the macro. The starting (high) number is the number of paragraphs selected plus one. Rather than using a SET field to set the starting number, this procedure places it in a document property, which is less likely to be deleted accidentally. It also allows for multiple reversed numbering lists in the same document, by incrementing a number at the end of the document property and sequence names. The field set is generated once, then stored as an AutoText entry for creating the remainder of the list, for two reasons:
- Inserting an AutoText entry is generally faster than recreating the field set.
- The code works with the Range object to insert the AutoText entry, rather than the Selection object used when creating the fields set, making it more accurate.
You will notice that the procedure to generate the field set, NewRevNumFieldSet, began as a recorded macro and uses the Selection object. Microsoft neglected to provide a VBA method to create nested fields. It isn't possible to include the field bracket characters as part of a string; they must be inserted separately. There are a number of approaches to the problem of creating nested fields, none of them particularly satisfactory from a developer standpoint. One is to record a macro, edit it judiciously, and test it very thoroughly. An alternate method based on the Range will be presented in the next installment of this series.
Hopefully, this article has animated you to explore how Word fields can render your documents more powerful. Part II of this series will continue to look at teaching Word how to overcome its limitations with the help of complex field sets.
Cindy Meister has her own consulting business, INTER-Solutions, based in Switzerland. Prior to becoming independent, she spent three years as a consultant/trainer for Deloitte & Touche in Zurich. Five years experience as head of administration in an international organization and a Bachelor of Science provide her with a broad background for understanding customer requirements. Cindy's fully bilingual (English and German), with customers in four countries (and counting) and is a regular contributor to the German edition of Inside Word. Four years as a Microsoft MVP for MSWord support and as Sysop in the CompuServe MSWord forum have given her in-depth knowledge of Microsoft Office and Word. For general questions on Word and links to other useful sites, visit her Web site at http://homepage.swissonline.ch/cindymeister. You can reach her at mailto:cindymeister@swissonline.ch.
' Number the selected
paragraphs in reverse order.
Sub
NumberInReverse()
Dim iStartNum As
Long
Dim sPropName As
String
Dim rngSelection As
Word.Range
Dim rngWork As Word.Range
Dim sATName As
String
Dim iCounter As
Long
Application.ScreenUpdating =
False
ActiveDocument.Windows(1).View.ShowFieldCodes =
False
' Get the
number of selected paragraphs.
iStartNum =
Selection.Paragraphs.Count
' Define a
DocProperty to hold the high number + 1.
sPropName =
CreateStartNumDocProp("StartNum", iStartNum)
' Save the
current selection in a range
' because
the selection will be changing.
Set rngSelection = Selection.Range
' Create
duplicate to work with.
Set rngWork = rngSelection.Duplicate
rngWork.Collapse
wdCollapseStart
' Create
and insert first number in sequence.
sATName =
CreateReverseOrderCounter(sPropName)
' Insert
remaining numbers at start of
' each
paragraph in selection.
For iCounter = 2 To
iStartNum
' Set working range to next paragraph.
Set rngWork =
rngSelection.Paragraphs(iCounter).Range
rngWork.Collapse
wdCollapseStart
ActiveDocument.AttachedTemplate.
_
AutoTextEntries(sATName).Insert
_
Where:=rngWork,
RichText:= True
Next
' Update
only fields in selection
'
(reverse-order numbering).
rngSelection.Fields.Update
End
Sub
' Returns DocProperty
name.
Function
CreateStartNumDocProp(ByVal sPropName,
_
ByVal PropValue As
Long) As
String
Dim prop As
Office.DocumentProperty
' If no
DocProperties, or none with StartNum in name
'
DocProperty name is StartNum1.
If
ActiveDocument.CustomDocumentProperties.Count = 0
Then
sPropName =
"StartNum1"
Else
' Otherwise, increment StartNum by 1.
For Each prop
In ActiveDocument. _
CustomDocumentProperties
If Left(prop.Name, 8) = "StartNum"
Then
sPropName =
_
"StartNum"
& CStr(Val(Mid(prop.Name, 9)) + 1)
Else
sPropName =
"StartNum1"
End If
Next prop
End If
' Create
DocProperty and set value to
' number
of selected paragraphs plus 1.
ActiveDocument.CustomDocumentProperties.Add
_
Name:=sPropName,
Type:=msoPropertyTypeString, _
Value:=
CStr(PropValue + 1), LinkToContent:=
False
CreateStartNumDocProp =
sPropName
End
Function
' Returns name of
AutoText entry that creates
' the reverse order
list.
Function
CreateReverseOrderCounter( _
ByVal sPropName As
String) As
String
Dim sRevNum As
String
Dim sATName As
String
sRevNum = Mid(sPropName, 9)
sATName = "SEQAT" &
sRevNum
' Create
the field set and insert
' first
one at beginning of selection
Selection.Collapse
wdCollapseStart
Call NewRevNumFieldSet(sPropName, "RevNum" & sRevNum)
' Create
an AutoText entry for rest of list
' because
inserting it will be faster and more accurate.
Selection.MoveRight
wdCharacter, 1, Extend:= True
ActiveDocument.AttachedTemplate.AutoTextEntries.Add
_
Name:=sATName,
Range:=Selection.Range
CreateReverseOrderCounter =
sATName
End
Function
' Recorded macro that
generates the set of nested fields
' for a sequence that
counts in reverse:
' { = {DocProperty
StartNum} - {SEQ RevNum} }
Sub
NewRevNumFieldSet(sProp, sRevNum)
'
Expression field
Selection.Fields.Add
Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:="= ", _
PreserveFormatting:=
False
' Show
field codes to position IP.
ActiveWindow.View.ShowFieldCodes =
True
Selection.MoveRight
Unit:=wdCharacter, Count:=4
Selection.Fields.Add
Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:="DOCPROPERTY " &
sProp, _
PreserveFormatting:=
False
Selection.TypeText Text:=" - "
Selection.Fields.Add
Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:="SEQ " & sRevNum,
_
PreserveFormatting:=
False
ActiveWindow.View.ShowFieldCodes =
False
Selection.Fields.Update
End
Sub