Microsoft Office 2000/Visual Basic Programmer's Guide   

The Range Object

A Range object represents a contiguous area in a document, defined by a starting character position and an ending character position. The contiguous area can be as small as the insertion point or as large as the entire document. It can also be, but does not have to be, the area represented by the current selection. You can define a Range object that represents a different area than the current selection. You can also define multiple Range objects in a single document. The characters in a Range object include nonprinting characters, such as spaces, carriage returns, and paragraph marks.

Note   The area represented by the current selection is contained in the Selection object. For information about using the Selection object, see "The Selection Object" later in this chapter.

A Range object is similar to a Word bookmark in that they both define a specific area within a document. However, unlike a bookmark, a Range object exists only so long as the code that creates it is running. In addition, when you insert text at the end of a range, Word automatically expands the range to include the new text. When you insert text at the end of a bookmark, Word does not expand the bookmark to include the new text. For more information about bookmarks, see "Working with Bookmarks" later in this chapter.

Creating, Defining, and Redefining a Range

You typically create a Range object by declaring an object variable of type Range and then instantiating that variable by using either the Document object's Range method or the Range property of another object, such as a Character, Word, Sentence, or Selection object. For example, the following code creates two Range objects that both represent the second sentence in the active document.

Public Sub GetRangeExample()
   ' This example shows how the Range method and the Range
   ' property both return the same characters.
   
   Dim rngRangeMethod        As Word.Range
   Dim rngRangeProperty      As Word.Range
   
   With ActiveDocument
      If .Sentences.Count >= 2 Then
            Set rngRangeMethod = .Range(.Sentences(2).Start, _
                .Sentences(2).End)
            Set rngRangeProperty = .Sentences(2)
      End If
   End With
   
   Debug.Print rngRangeMethod.Text
   Debug.Print rngRangeProperty.Text
End Sub

The GetRangeExample procedure is available in the modRangeCode module in WordSamples.doc in the ODETools\V9\Samples\OPG\Samples\CH05 subfolder on the Office 2000 Developer CD-ROM.

When you use the Range method to specify a specific area of a document, you use the method's Start argument to specify the character position where the range should begin and you use the End argument to specify where the range should end. The first character in a document is at character position 0. The last character position is equal to the total number of characters in the document. You can determine the number of characters in a document by using the Characters collection's Count property. As shown in the preceding example, you can also use the Start and End properties of a Bookmark, Selection, or Range object to specify the Range method's Start and End arguments. You can set the Start and End arguments to the same number. In this case, you create a range that does not include any characters.

You can set or redefine the contents of a Range object by using the object's SetRange method. You can specify or redefine the start of a range by using the Range object's Start property or its MoveStart method. Likewise, you can specify or redefine the end of a range by using the Range object's End property or its MoveEnd method.

The following example begins by using the Content property to create a Range object that covers the entire contents of a document. It then changes the End property to specify that the end of the range will be at the end of the first sentence in the document. It then uses the SetRange method to redefine the range to cover the first paragraph in the document. Finally, it uses the MoveEnd method to extend the end of the range to the end of the second paragraph in the document. At each step in the example, the number of characters contained in the range is printed to the Immediate window.

Public Sub RedefineRangeExample1()
   ' This procedure illustrates how to use various properties
   ' and methods to redefine the contents of a Range object.
   ' See also the RedefineRangeExample2 procedure.
   Dim rngSample As Range
   
   Set rngSample = ActiveDocument.Content
   
   With rngSample
      Debug.Print "The range now contains " & .Characters.Count _
            & " characters."
      .End = ActiveDocument.Sentences(1).End
      Debug.Print "The range now contains " & .Characters.Count _
            & " characters."
      .SetRange Start:=0, End:=ActiveDocument.Paragraphs(1).Range.End
      Debug.Print "The range now contains " & .Characters.Count _
            & " characters."
      .MoveEnd Unit:=wdParagraph, Count:=1
      Debug.Print "The range now contains " & .Characters.Count _
            & " characters."
   End With
End Sub

The RedefineRangeExample1 procedure is available in the modRangeCode module in WordSamples.doc in the ODETools\V9\Samples\OPG\Samples\CH05 subfolder on the Office 2000 Developer CD-ROM.

You can also redefine a Range object by using the object's Find property to return a Find object. The following example illustrates the use of the Find property to locate text within the active document. If the text is found, the Range object is automatically redefined to contain the text that matched the search criteria.

With rngRangeText.Find
   .ClearFormatting
   If .Execute(FindText:=strTextToFind) Then
      Set RedefineRangeExample2 = rngRangeText
   Else
      Set RedefineRangeExample2 = Nothing
   End If
End With

For more information about using the Find object, see "The Find and Replacement Objects" later in this chapter.

Many Word objects have a Range property that returns a Range object. You use an object's Range property to return a Range object under circumstances where you need to work with properties or methods of the Range object that are not available from the object itself. For example, the following code uses the Range property of a Paragraph object to return a Range object that is used to format the text in the first paragraph in a document:

Dim rngPara As Range

Set rngPara = ActiveDocument.Paragraphs(1).Range
With rngPara
   .Bold = True
   .ParagraphFormat.Alignment = wdAlignParagraphCenter
   .Font.Name = "Arial"
End With

After you identify the Range object, you can apply methods and properties of the object to modify the contents of the range or get information about the range. You use the Range object's StoryType property to determine where in the document the Range is located. For more information about the StoryType property, see "Knowing Where You Are" later in this chapter.

Watch Your Code Work

There are two important debugging tips you can use when writing VBA code that manipulates text. One is to make all nonprinting characters visible. This lets you see exactly what is happening to all characters as your code executes. The other tip is to have your code select objects before manipulating them. This creates a visual corollary between the object your code is manipulating and what is happening on screen.

To view all nonprinting characters, click Options on the Tools menu, click the View tab, and then select the All check box under Formatting Marks.

You can use the Range object's Select method to highlight its text, making it easier to see what the code is doing. To deselect the range, use the Range object's Collapse method. When you have finished debugging your code, remove the Select method code. If your code manipulates the Selection object, the object's text is highlighted by default. For more information about the Selection object, see "The Selection Object" later in this chapter.

Working with Text in a Range Object

You use a Range object's Text property to specify or determine the text the range contains. For example, the following code first displays the text within a Range object, then changes it and displays the new text, and finally restores the original text:

Public Sub ChangeTextSample()
   ' This procedure illustrates how to use the Range object's Text
   ' property to copy and paste text into a document while
   ' maintaining the original paragraphs.
   '
   ' When the rngText variable is instantiated, it includes all of
   ' the text in the first paragraph in the active document plus the
   ' paragraph mark at the end of the paragraph. Note how the new
   ' text in the strNewText variable includes a paragraph mark
   ' (vbCrLf) to replace the mark removed when the orginal text was
   ' replaced.
   Dim rngText               As Range
   Dim strOriginalText       As String
   Dim strNewText            As String
   
   strNewText = "Now is the time to harness the power of VBA in Word." _
      & "This text is replacing the original text in the first " _
      & "paragraph. This is all done using only the Text property " _
      & "of the Range object!" _
      & vbCrLf
      
   Set rngText = ActiveDocument.Paragraphs(1).Range
   With rngText
      MsgBox .Text, vbOKOnly, "This is the original text."
      strOriginalText = .Text
      .Text = strNewText
      MsgBox .Text, vbOKOnly, "This is the new text inserted in paragraph 1."
      .Text = strOriginalText
      MsgBox "The original text is restored."
   End With
End Sub

In this example, the Range object's Text property is used to specify the text that appears in the document. The ChangeTextSample procedure is available in the modRangeCode module in WordSamples.doc in the ODETools\V9\Samples\OPG\Samples\CH05 subfolder on the Office 2000 Developer CD-ROM. To see examples of simple procedures that use the Range object to replace text, or portions of text, in a document, open the WordSamples.doc sample file and click the buttons on the Range Examples menu of the Working with Word Objects toolbar.

Knowing Where You Are

You can use the Range object's StoryType property to determine where the range is located. Stories are distinct areas of a document that contain text. You can have up to 11 story type areas in a document, representing areas such as document text, headers, footers, footnotes, comments, and more. You use the StoryRanges property to return a StoryRanges collection. The StoryRanges collection contains Range objects representing each story in a document.

A new Word document contains a single story, called the Main Text story, which represents the text in the main part of the document. Even a blank document contains a character, a word, a sentence, and a paragraph.

You do not expressly add new stories to a document but rather, Word adds them for you when you add text to a portion of the document represented by one of the 11 story types. For example, if you add footnotes, Word adds a Footnotes story. If you add comments, Word adds a Comments story to the document.

You use the Range property to return a Range object representing each story in a document. For example, the following code prints the text associated with the Main Text story and the Comments story:

Dim rngMainText         As Word.Range
Dim rngCommentsText     As Word.Range

Set rngMainText = ActiveDocument.StoryRanges(wdMainTextStory)
Set rngComments = ActiveDocument.StoryRanges(wdCommentsStory)
Debug.Print rngMainText.Text
Debug.Print rngComments.Text

To work with a code sample that shows how to access all StoryRanges collection members and their related properties, see the StoryRangeTest procedure in the modRangeCode module in WordSamples.doc in the ODETools\V9\Samples\OPG\Samples\CH05 subfolder on the Office 2000 Developer CD-ROM.

Understanding Paragraph Marks — They're Not Just Carriage Returns

When you work with text programmatically, it is important to understand how Word handles paragraph marks. At a basic level, a Word document is nothing more than a vast collection of characters. We tend to think of documents as collections of words, sentences, and paragraphs, but basically all you really have are characters. Each character has a specific job to do. Some characters are letters, spaces, or tabs. Some characters are paragraph marks or page breaks.

Paragraph marks play a unique and sometimes misunderstood role in Word documents. A paragraph consists of a paragraph mark and all text that precedes the mark up to, but not including, a previous paragraph mark. In addition — and this is the important part — a paragraph mark contains all the information about how the paragraph is formatted.

When you copy a word, sentence, or paragraph and you include a paragraph mark, all the formatting information contained in the paragraph mark is also copied and applied to the paragraph when it is pasted in another location.

If you want to copy text from within one paragraph and paste it into another paragraph but do not want to copy the paragraph formatting as well, make sure that you do not copy the paragraph mark adjacent to the text you copy.

Every blank Word document contains a single paragraph mark that constitutes a Character object, a Word object, a Sentence object, and a Paragraph object all at the same time. However, the Statistics tab of the Properties dialog box (File menu) reports that there are no characters, words, sentences, or paragraphs in a blank document. This difference highlights an important aspect of Word that you will need to consider when manipulating these objects programmatically. To see a procedure that illustrates these differences, see the WhatIsInThisDocument procedure in the modRangeCode module in WordSamples.doc in the ODETools\V9\Samples\OPG\Samples\CH05 subfolder on the Office 2000 Developer CD-ROM.

In the ChangeTextSample procedure shown in "Working with Text in a Range Object" earlier in this chapter, note how the text in the strNewText variable uses the vbCrLf built-in constant to create a paragraph mark at the end of the text that will replace the existing text in paragraph 1 of the active document. This is done to prevent the new text from becoming part of the second paragraph.

When you create a Range object that represents a Character, Word, or Sentence object and that object falls at the end of a paragraph, the paragraph mark is automatically included within the range. Moreover, the Range object will include all additional subsequent empty paragraph marks. For example, in a document where the first paragraph consists of three sentences, the following code creates a Range object that represents the last sentence in the first paragraph:

Set rngCurrentSentence = ActiveDocument.Sentences(3)

Because the rngCurrentSentence Range object refers to the last sentence in the first paragraph, that paragraph mark (and any additional empty paragraph marks) will be included in the range. If you then set the Text property of this object to a text string that didn't end with a paragraph mark, the first and second paragraphs in the document would be deleted.

When you write VBA code that manipulates text in a Word document, you need to account for the presence of a paragraph mark in your text. There are two basic techniques you can use to account for paragraph marks when you are cutting and pasting text in Range objects:

In this example, the Count property of the Range object's Characters collection is used to redefine the Range object's end point. The IsLastCharParagraph procedure is available in the modRangeSimpleCode module in WordSamples.doc in the ODETools\V9\Samples\OPG\Samples\CH05 subfolder on the Office 2000 Developer CD-ROM.

Inserting Text in a Range

You use the Range object's InsertBefore or InsertAfter methods to add text to an existing Range object. In fact, there is an entire class of methods, with names that begin with "Insert," that you can use to manipulate a Range object. For complete information about all the Range object's properties and methods, search the Microsoft Word Visual Basic Reference Help index for "Range object."

Note   All the methods and properties discussed in this section also apply when you are working with text in the Selection object. For more information about the Selection object, see "The Selection Object" later in this chapter.

It's useful to have a procedure that combines the Range object's InsertBefore and InsertAfter methods with the Text property. Having such a procedure creates a single place to handle much of the work you will do when manipulating text programmatically. The InsertTextInRange procedure in the clsManipulateText module in WordSamples.doc in the ODETools\V9\Samples\OPG\Samples\CH05 subfolder on the Office 2000 Developer CD-ROM is just such a procedure. The InsertTextInRange procedure is contained in a class module and is exposed as a method of the class to make it even easier to use in any Word solution you develop. For more information about creating custom class objects, see Chapter 9, "Custom Classes and Objects."

You can call the InsertTextInRange procedure any time you need to add text to a Range object. In other words, the procedure is useful any time you want to programmatically make any changes to existing text in a Word document.

The InsertTextInRange procedure uses two required arguments and one optional argument. The strNewText argument contains the text you want to add to the Range object specified in the rngRange argument. The intInsertMode optional argument specifies how the new text will be added to the range. The values for this argument are one of three custom enumerated constants that specify whether to use the InsertBefore method, the InsertAfter method, or the Text property to replace the existing range text.

Public Function InsertTextInRange(strNewText As String, _
                               Optional rngRange As Word.Range, _
                               Optional intInsertMode As opgTextInsertMode = _
                               Replace) As Boolean
   ' This procedure inserts text specified by the strNewText
   ' argument into the Range object specified by the rngRange
   ' argument. It calls the IsLastCharParagraph procedure to
   ' strip off trailing paragraph marks from the rngRange object.
 
   Call IsLastCharParagraph(rngRange, True)
   
   With rngRange
      Select Case intInsertMode
         Case 0 ' Insert before text in range.
            .InsertBefore strNewText
         Case 1 ' Insert after text in range.
            .InsertAfter strNewText
         Case 2 ' Replace text in range.
            .Text = strNewText
         Case Else
      End Select
      InsertTextInRange = True
   End With
End Function

Note that the IsLastCharParagraph procedure is used to strip off any final paragraph marks before inserting text in the range. The IsLastCharParagraph procedure is discussed in "Understanding Paragraph Marks — They're Not Just Carriage Returns" earlier in this chapter.