Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
DiscussionsAccessExcelInfoPathOutlookPowerPointPublisherWord
DirectoryUser Groups
Related Topics
Outlook ExpressInternet ExplorerWindowsMS Server ProductsMore Topics ...

MS Office Forum / Word / Programming / July 2007

Tip: Looking for answers? Try searching our database.

MsgBox showing number of replacements for all affected story ranges,  not just the main story

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
andreas - 27 Jun 2007 10:07 GMT
Hello everybody,

I recently wrote a macro that indicates the number of replacements of
a search and replace operation in a MsgBox.

It is working fine, but the trouble is that it covers only the number
of replacements of the main story range. Is it possible for somebody
to re-write the code to include ALL THE STORY RANGES of the document,
so that the MsgBox shows the TOTAL NUMBER OF REPLACEMENTS OF ALL STORY
RANGES?
I tried it several times, but to  no avail.
Help is much appreciated. Thank you very much in advance. Regards,
Andreas

Sub ReplacementOperatonWithMsgBoxShowingNumberOfReplacements
Dim rng As Word.Range
Dim bfound As Boolean, i As Long
'start counter at -1
i = -1
Do

   Set rng = ActiveDocument.Range

       With rng.Find
       .ClearFormatting
       .Replacement.ClearFormatting
       .MatchWildcards = True
       'Check if word is found
       bfound = .Execute(findtext:="find", replaceWith:="lost",
Replace:=wdReplaceOne)
       'increment counter
       i = i + 1
   End With
Loop While bfound
MsgBox CStr(i) & " replacements made."

Set rng = Nothing
End Sub
Bear - 27 Jun 2007 15:28 GMT
Adreas and Shauna:

This example illustrates two of the most baffling features of VBA.

First, the example code Shauna refers to says:

   myStoryRange.Find.Execute FindText:="Microsoft Word", Forward:=True
   While myStoryRange.Find.Found
       myStoryRange.Italic = True
       myStoryRange.Find.Execute _
           FindText:="Microsoft Word", Forward:=True
   Wend

Before executing the first line of this code, myStoryRange is the first
story range in the document, say the main body story.

When there's a hit, after executing the first line myStoryRange becomes the
found text. So for the second and third lines, myStoryRange is the found text.

Now in the fourth line, without any action on our part, myStoryRange
suddenly no longer means the found text, but the original range -- or maybe
the original range with the start collpsed to the end of the found text. WHY?

Second, I know that code like:

For Each myStoryRange in ActiveDocument.StoryRanges
   myStoryRange processing
Next myStoryRange

...will NOT work through every story range, and that the odd:

While Not (myStoryRange.NextStoryRange Is Nothing)

...is needed to progress through the collection. WHY?

I've accepted both behaviors, but I'd really welcome any insight that helps
me understand, rather than simply accept.

Bear

Signature

Windows XP, Word 2000

Shauna Kelly - 28 Jun 2007 09:33 GMT
Hi Bear

Good questions! And the answers, in the end are "because someone at
Microsoft just did it that way".

QUESTION 1

There are lots of different ways of laying out code, especially code to find
text in a Word document. So I've re-arranged this a bit to make it easier to
see what's going on. And I've added voluminous comments. Sadly, Microsoft's
example code never explicitly establishes its variables. It's worth knowing
that the myStoryRange in the following is a Range object. One really should
create the variable explicitly, as I've done here.

Sub FindStuff

'Declare our variable
Dim myStoryRange As Range

'Before the next bit of code would work, we have to set the myStoryRange to
something
'(In the original, it cycles through all the StoryRanges)
Set myStoryRange = ActiveDocument.StoryRanges.Item(wdMainTextStory)

'Use myStoryRange (which is the main text story) and do stuff with Finding
With myStoryRange.Find
   'Identify what to find
   .Text = "Microsoft Word"

   'Identify whether to search top-to-bottom or bottom-to-top
   .Forward = True

   'Tell Word what to do when it's finished searching. Specifically:
   '(from the help file) what happens if the search begins at a point
   'other than the beginning of the document and the end of the document
   'is reached (or vice versa if Forward is set to False) or if the search
   'text isn't found in the specified selection or range.
   '
   'The wdFindContinue setting is the default. So in Microsoft's code
   'example they could omit it. That's fine for computers, but we
   'humans might like to know what's going on.
   '
   'The .Wrap property works like the prompt you get in the UI if
   'you select a range and do a search-and-replace within the range.
   'Word asks if you want to continue searching in the rest of the
document.
   '
   'For what it's worth, if you want to restrict your search to a specific
   'range, choose .Wrap = wdFindStop.
   '
   'So, we tell Word to keep searching after this Find.
   '
   .Wrap = wdFindContinue

   'Go see if you can find anything
   .Execute

   'If Word found the text, then the myStoryRange object (which is
   'just a Range object) is now re-assigned to the range where
   'Word found the text it was looking for.
   '
   'However, if Word did not find the text, then myStoryRange
   'is the same as it ever was.
   '
   'That's just how it works. The VBA help file explains much of this.

   'We haven't yet looked to see if Word found the text.
   'We can detect that using myStoryRange.Find.Found.
   'If that is true, then Word found our text.

   'If Word reported that it found something, then do this stuff.
   While .Found
       'If we found our text, then myStoryRange has been re-assigned
       'to the text we found. Make it Italic.
        myStoryRange.Italic = True

        'Quick reminder:
        'The .Forward setting is still True.
        'The .Wrap setting is still wdFindContinue
        'So, if we haven't hit the end of the document, Word will
        'keep looking in the document.

        'Go see if you can find another instance of our text
        .Execute

        'And if Word finds another instance of our text, then
        '.Found will be true
        'and myStoryRange will have been re-assigned to the
        'newly-found text.

        'So, if .Found is true, we'll loop here.
        'If .Found is false, Word will kick us out of the loop
        'and we can go home.

   Wend

End With

EndSub

QUESTION 2

Here's an illustrated version of code to cycle through StoryRanges. I've
used a separate variable here for the 'inner' story ranges, where Microsoft
only uses one. And I've tried to make some things more explicit - it's not
necessarily good programming practice, it's just designed for illustration.
And I will count myself as having succeeded if, after working through this,
you no longer think that "While Not (myStoryRange.NextStoryRange Is
Nothing)" is Odd<g>.

Sub CycleThroughStoryRanges()

Dim myStoryRange As Range
Dim mySubRange As Range

'Go through every StoryRange (there are exactly 17 of them
'in Word 2003)
For Each myStoryRange In ActiveDocument.StoryRanges
   'Do some stuff to this myStoryRange object
   If myStoryRange.Paragraphs.Count > 0 Then
       MsgBox myStoryRange.Paragraphs(1).Range.Text
   End If

   'But some stories have 'followers'. Eg if the document has more than
   'one section, there may be many even page headers in the document.
   'And we want to cycle through them all.

   'Trap an error if the .NextStoryRange doesn't exist.
   'For example, if myStoryRange is the even headers story, then there
might
   'not be a Next even header. And the VBA Help for NextStoryRange explains
   'that when myStoryRange is (eg) the footnotes story, then
.NextStoryRagne
   'will always return Nothing.
   On Error Resume Next
   Set mySubRange = myStoryRange.NextStoryRange
   On Error GoTo 0

   If mySubRange Is Nothing Then
       'There is no 'next' story - so if myStoryRange were, say,
       'an even pages header, then there is no next even pages
       'header. Or maybe, eg, myStoryRange is the footnotes, and
       'it has no .NextStoryRange. So we can give up and go on.
   Else
       'We're here because mySubRange is *not* a Nothing

       'While we continue to have more than Nothing, do this stuff
       While Not (mySubRange Is Nothing)
           'Do some stuff to this 'follower' range
           If myStoryRange.Paragraphs.Count > 0 Then
               MsgBox mySubRange.Paragraphs(1).Range.Text
           End If

           'See if we can find yet another 'follower' range
           '(eg the next even header)
           On Error Resume Next
           Set mySubRange = mySubRange.NextStoryRange
           On Error GoTo 0

           'If we've found another 'follower' range (eg another
           'even pages header), then we'll loop here.
           'Otherwise, Word will kick us out of this inner loop
           'and we'll go on to the next (top-level) myStoryRange.

       Wend
   End If
Next myStoryRange

End Sub

Signature

Hope this helps.

Shauna Kelly.  Microsoft MVP.
http://www.shaunakelly.com/word

> Adreas and Shauna:
>
[quoted text clipped - 40 lines]
>
> Bear
Bear - 28 Jun 2007 14:38 GMT
Shauna:

Thanks for your efforts. I'm not sure you've done more than beautifully
illuminate the odd nature of the DOM and VBA's interaction with it. But I'll
reread your code a few times to make sure I'm getting your points.

I DID get a new perspective on story ranges. Tell me if any of this is
wrong...

When you say of story ranges "there are exactly 17 of them in Word 2003" I
think you mean to say that there are 17 types of story range. The might be
any number of story ranges in a given document?

For whatever reason, "For Eaching" through the story range collection only
yields the first story range of each type, so the "inner" loop with the test
for Is Nothing is needed to process subsequent story ranges within a given
type.

Bear
Signature

Windows XP, Word 2000

Shauna Kelly - 30 Jun 2007 04:45 GMT
Hi

You have it exactly right--at least as I understand it.

You can see the 17 types if you look in VBA help under the Item Method for
the StoryRanges object. That lists 11 of them. But if you type
ActiveDocument.StoryRanges.Item( into the VBE, the intellisense lists 17 of
them. And the object browser lists 17.

I think that the apparently convoluted nature of the StoryRanges is because
(for example) a document has exactly one main story, it might or might not
have comments, and it might have any number of different headers and
footers.

Hope this helps.

Shauna Kelly.  Microsoft MVP.
http://www.shaunakelly.com/word

> Shauna:
>
[quoted text clipped - 17 lines]
>
> Bear
andreas - 01 Jul 2007 09:13 GMT
On 30 Jun., 05:45, "Shauna Kelly"
<ShaunaKe...@SendNoSpamToShaunaKelly.com> wrote:
> Hi
>
[quoted text clipped - 39 lines]
>
> - Zitierten Text anzeigen -

Shauna and Bear,

great comments from both of you. Very helpful.  Thank you so much.

Regards,

Andreas
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.