Solution - Novice Challenge 9: I Need a Break

It’s true: we all need a break once in a while. A break from work, a break from the kids, a break from the in-laws...sometimes we just need to power down for a little while and take it easy. But sometimes this can be overdone. The breaks at work come a little too often, or the parents say that you’re not calling often enough.

Note. What? No, we don’t know anyone like that, and we definitely don’t know anyone who takes too many breaks at work. But we’re sure they’re out there somewhere.

Usually none of this is too bad, but what happens when your software takes too many breaks? That’s definitely trouble. And that’s exactly what happened in Challenge 9. We have a Word document that has way too many manual page breaks, and we need to get rid of some of them. As a matter of fact, we need to get rid of all of them. That should be easy, right?

But, then again, we didn’t want to make challenge too easy on you. Given the fact that you could have get rid of the manual page breaks by simply recording a macro, we threw in an extra requirement: you had to display a couple of message boxes along the way. Here’s how we accomplished all that:

Sub FindMyBreaks()

 

Dim objPages As Pages

 

'Retrieve a collection of all the pages in the document

Set objPages = ActiveDocument. _

    ActiveWindow.Panes(1).Pages

   

'Display a message box showing the number of pages in the doc.

MsgBox "Number of Pages: " & objPages.Count, vbOKOnly, "Document Pages"

 

'Ensures all instances of the search string are found, regardless of formatting

Selection.Find.ClearFormatting

 

'Find manual page breaks and paragraph markers that follow them and replace

' with nothing.

With Selection.Find

    .Text = "^m^p"

    .Replacement.Text = ""

    .Forward = True

    .Wrap = wdFindContinue

End With

Selection.Find.Execute Replace:=wdReplaceAll

   

'Retrieve a collection of all the pages with the manual page breaks removed.

Set objPages = ActiveDocument. _

    ActiveWindow.Panes(1).Pages

 

'Display a message box showing the number of pages in the doc.

MsgBox "Number of Pages: " & objPages.Count, vbOKOnly, "Document Pages"

 

End Sub

 

After declaring the one variable we’re going to need in this subroutine (objPages), we use the Pages collection to retrieve a collection of all the pages in the current document:

Set objPages = ActiveDocument. _

    ActiveWindow.Panes(1).Pages

Now we can accomplish the first step in the instructions for Challenge 9. We need to display a message box that states the number of pages in the current document. We do that by calling the MsgBox function like this:

MsgBox "Number of Pages: " & objPages.Count, vbOKOnly, "Document Pages"

We pass three parameters to MsgBox. The first is the text we want displayed within the message box:

"Number of Pages: " & objPages.Count

Here we’re creating a string that begins with “Number of Pages:”. We then tack on the number of pages. And how did we get the number of pages? Well, we just retrieved a collection of all the pages, so all we have to do at that point is count them. In other words, we just need to take a look at the Count property of the Pages collection.

Next it’s time to get to work removing those page breaks. The first thing we do is call the ClearFormatting method of the Find object:

Selection.Find.ClearFormatting

We do this just to make sure we find all our page breaks, no matter what formatting may have been applied to them.

In order to remove the page breaks, we need to find them all and then replace them with nothing. So the next thing we do is set up the find and replace criteria:

With Selection.Find

    .Text = "^m^p"

    .Replacement.Text = ""

    .Forward = True

    .Wrap = wdFindContinue

End With

Because all of our settings will be applied to the Selection.Find object, we put everything inside a With block; that way we don’t have to keep typing Selection.Find over and over again. (Hey, we’re busy people, we don’t have time for all that typing. Maybe later, when we get a break, we’ll think about doing some more typing.)

We set four properties for our find and replace. First we set the Text property, which specifies the string we want to search for:

.Text = "^m^p"

Wait a minute: didn’t we say we were looking for a page break, not the string ^m^p? Well, as it turns out, the character set ^m represents a manual page break. (How do we know this? In Word, open the Find and Replace dialog box. Click More>> , click Special, and then select Manual Page Break. You’ll see the characters ^m in the Find what text box.)

To solve this challenge (and receive your goldfish) that’s all you had to search for. But when we ran find and replace with ^m as the text string, we wound up with extra paragraph breaks in our text. Therefore we added ^p to our string, which represents a paragraph mark. Thus we’re searching for both a manual page break and the paragraph return that follows it.

Now that we’ve set the text we want to find, we set the value of the Replacement.Text property to the value we want to use as the replacement text. In our case we just want to delete the page break, so we replace it with an empty string (nothing):

.Replacement.Text = ""

We’re starting our find and replace from the beginning of the document, so we set the Forward property to True, saying we want to do a forward search (rather than start at the end and search backwards):

.Forward = True

Finally, we set the Wrap property to the constant wdFindContinue:

.Wrap = wdFindContinue

We’ve all seen this before: we’re somewhere in the middle of the document, we do a Find, and when we reach the end of the document Word pops up a box asking if we’d like to continue searching from the top. Setting the Wrap property to wdFindContinue is like clicking Yes to that dialog box. In other words, if our search reaches the end of the document before the whole document has been searched, the search will automatically continue from the beginning. This is nice, because we don’t want any stray message boxes popping up in middle of running our macro.

We’ve now set all the properties for our find and replace, which means it’s time to actually run it:

Selection.Find.Execute Replace:=wdReplaceAll

As you can see, we’re calling the Execute method on the Find object to run our find and replace. Note that we set the Replace parameter to wdReplaceAll; this ensures that every instance of the find string will be replaced, not just the first one.

Okay, we’ve done the hard part; now there’s only one thing left to do. Now that we’ve removed all the manual page breaks, we want to see how many pages we’re left with. That’s actually pretty simply. We just run the exact same code we ran at the beginning of the subroutine to retrieve all the pages, then output the page count to a message box:

Set objPages = ActiveDocument. _

    ActiveWindow.Panes(1).Pages

 

MsgBox "Number of Pages: " & objPages.Count, vbOKOnly, "Document Pages"

Because we’re calling the same code twice, it might be a good idea to put that section of code in a new subroutine and simply call the subroutine twice. But we put in the instructions for these challenges that we didn’t want you to do that (it’s much easier to test single subroutines); because of that, we asked you to break a useful coding standard for ease of testing. We just thought we’d mention that when you’re coding for real and not playing OfficePalooza games, this type of thing would be a good candidate for creating an additional subroutine.

That’s the lesson for today, and the end of Challenge 9. We’re going to take a break now. See you later.