Can you help out with my formatting problem

P

Patrick Finucane

Bear with me, there is a reason for what I need to do. I have a
document template with mail merge fields. This form will be mail merged
from Access and saved. A situation may come up where I need to grab the
data between the salutation and the Sincerely and paste it into the new
document. This is my first attempt at working with Word VBA...I'm
hoping you can spot what I need to do.

Ex of the document:
Joe Blow
123 Somewhere St
Anywhere USA 12345<BodyTextStart Bookmark>

blah blah blah
blah blah blah

<BodyTextEnd Bookmark>Sincerely,
Jane Doe

The lines of blah, blah, blah are the body text. I put in a couple of
bulleted items and bolded a couple of workds and ran the tollowing
code. It WORKS!!!!...except the bolding gets lost and and bullets are
gone...just the text. Can you help out?

Sub testDocument()
On Error GoTo ErrorHandler
Dim lngStart As Long
Dim lngEnd As Long
Dim aRange As Range

'bookmark where the body of the letter will start and end
lngStart = ActiveDocument.Bookmarks("BodyTextStart").Start
lngEnd = ActiveDocument.Bookmarks("BodyTextEnd").Start - 1

'define the range
Set aRange = ActiveDocument.Range(Start:=lngStart, End:=lngEnd)

'I set a range to BodyTextEnd and did an edit paste but
'it overwrote the Sincerely stuff. I need to insert, not paste over
'aRange.Select
'aRange.Copy
'aRange.Paste

'the following line does not work or compile but from what
'I read, PasteSpecial does what I want this routine to do (I think).
'aRange.InsertAfter aRange.PasteSpecial DataType:=wdPasteText

'these are close but no cigar..the formatting of bold and bullets
not there
'aRange.InsertAfter aRange.FormattedText.Duplicate
'or this
'aRange.InsertAfter aRange.FormattedText

MsgBox "Done"

Exit_Test:
Exit Sub

ErrorHandler: ' Error-handling routine.
If Err.Number = 5941 Then
MsgBox "One of the bookmarks does not exit"
Else
MsgBox Err.Description
End If
Resume Exit_Test
End Sub
 
J

Jay Freedman

Hi, Patrick,

You're close, but don't try to do it all with just one Range object. Try
this instead:

Sub testDocument()
On Error GoTo ErrorHandler
Dim lngStart As Long
Dim lngEnd As Long
Dim aRange As Range, destRange As Range

'bookmark where the body of the letter will start and end
lngStart = ActiveDocument.Bookmarks("BodyTextStart").Start
lngEnd = ActiveDocument.Bookmarks("BodyTextEnd").Start - 1

'define the range
Set aRange = ActiveDocument.Range(Start:=lngStart, End:=lngEnd)

'define the destination
Set destRange = aRange.Duplicate
destRange.Collapse direction:=wdCollapseEnd

'copy the stuff
destRange.FormattedText = aRange.FormattedText

MsgBox "Done"

Exit_Test:
Exit Sub

ErrorHandler: ' Error-handling routine.
If Err.Number = 5941 Then
MsgBox "One of the bookmarks does not exit"
Else
MsgBox Err.Description
End If
Resume Exit_Test
End Sub
 
P

Patrick Finucane

Jay Freedman wrote:

Hi Jay. I think you put me on the right track. Could you take a look
at my code below yours. See if it makes sense? It appears to
work...but you may have some pointers.
Hi, Patrick,

You're close, but don't try to do it all with just one Range object. Try
this instead:

Sub testDocument()
Dim lngStart As Long
Dim lngEnd As Long
Dim aRange As Range, destRange As Range

'bookmark where the body of the letter will start and end
lngStart = ActiveDocument.Bookmarks("BodyTextStart").Start
lngEnd = ActiveDocument.Bookmarks("BodyTextEnd").Start - 1

'define the range
Set aRange = ActiveDocument.Range(Start:=lngStart, End:=lngEnd)

'define the destination
Set destRange = aRange.Duplicate
destRange.Collapse direction:=wdCollapseEnd

'copy the stuff
destRange.FormattedText = aRange.FormattedText

MsgBox "Done"

End Sub

What occurs is I have a master document. I save Master.Doc to Test.Doc
and do the merge. At this point, the user enters the body text. The
doc is saved. Later on, the useer decides to make a copy of the master
doc, merge the fields, and saves this as Test1.Doc. The body text from
Test.Doc is then pasted into Test1.Doc. With your help, I got this far
and it appears to function correctly. I'm not sure about the
Drange.Delete line..is there a methodology that will do it better and
cleaner. Thanks once again!!!!

Sub testDocument()
'I'm running this with Test.Doc open.
Dim lngStart As Long
Dim lngEnd As Long
Dim aRange As Range
Dim dRange As Range
Dim doc As Document

'bookmark where the body of the letter will start and end
lngStart = ActiveDocument.Bookmarks("BodyTextStart").Start
lngEnd = ActiveDocument.Bookmarks("BodyTextEnd").Start - 1

'define the range for doc to copy body text
Set aRange = ActiveDocument.Range(Start:=lngStart, End:=lngEnd)

'test1 is mail merged at this point but has no body text
Set doc = Application.Documents.Open("C:\Temp\Test1.Doc")

'you used Duplicate here when defining DRange. I'm not sure if I
can use it here.
'I basically define the body text area and delete any exising line
breaks
'between the last address line and the word Sincerely
lngStart = doc.Bookmarks("BodyTextStart").Start
lngEnd = doc.Bookmarks("BodyTextEnd").Start - 1
Set dRange = doc.Range(Start:=lngStart, End:=lngEnd)
dRange.Delete lngEnd - lngStart

dRange.Collapse direction:=wdCollapseStart
dRange.FormattedText = aRange.FormattedText
doc.Save
doc.Close
Set doc = Nothing
MsgBox "Done"

End Sub
 
J

Jay Freedman

Hi, Patrick,

Sorry, I thought you were trying to paste the text into the same document at
the end of the original range.

Your latest version will work just fine. I don't think the dRange.Delete
statement needs the "lngEnd - lngStart" part, but it doesn't hurt. Also,
after the .Delete, dRange should already be collapsed so you don't really
need the dRange.Collapse statement; but again, it doesn't hurt.
 
J

Jay Freedman

Patrick said:
Great.

One more question. I used the variable "wdCollapseStart". Is there a
location in Help were the actual values of "wdCollapseStart" or
"wdCollapseEnd" and other constants are displayed? In Access help,
arguments and their values are listed. Running the code you helped
me on from Access, without dimming the variables first and assigning a
value, chokes. I've been using the Immediate window in the Word
editor to get the values...ex:
? wdCollapseStart

Hi, Patrick,

This isn't any faster than the Immediate window, but it will show that value
plus all other related constants:

In the VBA editor, press F2 (or use View > Object Browser). Type or paste
the constant's name into the search window (unmarked, but it's the one to
the left of the binoculars icon) and click the binoculars or press Enter.
The bottom pane will show the constant's value.

This is also good for tracking down constants when you only know part of
their name. For example, you could search on "collapse" to find everything
in VBA that contains that word.
 
P

Patrick Finucane

Thanks...mucho gusto.

Jay said:
Hi, Patrick,

This isn't any faster than the Immediate window, but it will show that value
plus all other related constants:

In the VBA editor, press F2 (or use View > Object Browser). Type or paste
the constant's name into the search window (unmarked, but it's the one to
the left of the binoculars icon) and click the binoculars or press Enter.
The bottom pane will show the constant's value.

This is also good for tracking down constants when you only know part of
their name. For example, you could search on "collapse" to find everything
in VBA that contains that word.
 
P

Patrick Finucane

You've been a lot of help. I don't want to keep bugging you for
answers, so this will probably be my last question for awhile. You know
my situation; I have a letter that contains some body text that I want
to copy to another letter. That's solved.

The original master body text is entered in one letter and then saved
then I can use the body text. Looking at the situation, I am
considering making up several documents that contains parts of the body
text. I'll call these boilerplate templates. I envision the user
selecting 0, 1, or many boilerplates. Then when I create the doc for
the first customer, I run through the list of boilerplate items selected
and insert the text from the boilerplates into the document 1 after
another. The user can then brush it up, save it, and then addtional
letters to other customers can use that letter to insert the text.

I was thinking I could "set" bookmarks. Do I really need a bookmark
name within the document or can I set a book mark via a Set command via
a position in the document. I didn't see any reference to
Insert/Bookmark/Add. Would I use SetRange.

If I opendup a boilerplate document, is there an easy command that would
basically do an Edit/SelectAll or an easy method to copy the contents of
that document into it?

If I am adding multiple boilerplates to the one document, the range
would expand each time. Since the word Sincerely will always be the
ending point of the body text, can I find the last location of Sincerely
in the document?

I guess a summary is:
Do ranges need to be named or can I simply us a number?
Best method to insert text from another document...the whole document
will be inserted...as it may be just 1 paragraph or several
Best method to find a word to determine the ending point of a range.

I won't need to do this right away, but I have a funny feeling once the
folks see the stuff you helped me on, they'll want to use this method
too.
 
J

Jay Freedman

Hi, Patrick,

Before you start banging your head against a wall -- and believe me, a
project like this will do it for you, even if you aren't a novice
programmer! -- consider not reinventing the wheel. MVP Bill Coan offers an
add-in called MySubjectMatter that will handle this task with ease
(http://www.wordsite.com/MySubjectMatter.html). Although I'm not familiar
with it, there's also an application called Pathagoras
(http://www.pathagoras.com).

If you still want to go through with it, see the inline comments below.

Patrick said:
You've been a lot of help. I don't want to keep bugging you for
answers, so this will probably be my last question for awhile. You
know my situation; I have a letter that contains some body text that
I want to copy to another letter. That's solved.

The original master body text is entered in one letter and then saved
then I can use the body text. Looking at the situation, I am
considering making up several documents that contains parts of the
body text. I'll call these boilerplate templates. I envision the
user selecting 0, 1, or many boilerplates. Then when I create the
doc for the first customer, I run through the list of boilerplate
items selected and insert the text from the boilerplates into the
document 1 after another. The user can then brush it up, save it,
and then addtional letters to other customers can use that letter to
insert the text.

I was thinking I could "set" bookmarks. Do I really need a bookmark
name within the document or can I set a book mark via a Set command
via a position in the document. I didn't see any reference to
Insert/Bookmark/Add. Would I use SetRange.

Sorry, I don't understand what you're proposing. A VBA routine can put text
anywhere in a document, as long as you can "tell it" how to find the right
spot. That could be by using a bookmark or a field, or by doing a .Find for
specific text or formatting, or by saying "go to the end of the document",
or.... Once you have the Range object assigned to the proper spot, you just
say oRange.Text = MyString, or oRange.FormattedText =
otherRange.FormattedText, or insert an IncludeText field, or....
If I opendup a boilerplate document, is there an easy command that
would basically do an Edit/SelectAll or an easy method to copy the
contents of that document into it?

Set BoilerDoc = Documents.Open(blahblah)
Set otherRange = BoilerDoc.Range
oRange.FormattedText = otherRange.FormattedText

Alternatively, to "link" in the text rather than actually pasting it into
the document,

MyDoc.Fields.Add Range:=oRange, Type:=wdFieldIncludeText, _
Text:="c:\\docfolder\\boilerdoc.doc"
If I am adding multiple boilerplates to the one document, the range
would expand each time. Since the word Sincerely will always be the
ending point of the body text, can I find the last location of
Sincerely in the document?

Set oRange = MyDoc.Range
oRange.Collapse wdCollapseEnd
With oRange.Find
.ClearFormatting
.Text = "Sincerely"
.Forward = False
.Wrap = wdFindStop
.MatchWildCard = False
If Not .Execute Then
MsgBox "Document has no Sincerely"
Exit Sub
End If
End With
' at this point, oRange covers the word Sincerely
oRange.Collapse wdCollapseStart
I guess a summary is:
Do ranges need to be named or can I simply us a number?
Best method to insert text from another document...the whole document
will be inserted...as it may be just 1 paragraph or several
Best method to find a word to determine the ending point of a range.

I won't need to do this right away, but I have a funny feeling once
the folks see the stuff you helped me on, they'll want to use this
method too.

Have them try out MySubjectMatter.
 
P

Patrick Finucane

Hi Jay:

Thanks for your advice. I understand what you are saying. And I'll
check out your references. Seriously, I think I need to sit down at
www.mvps.org and read everything I can on WOrd and then get a good book
on Word Basic. I don't ever expect to become an "expert" in Word,
simply be able to manipulate it to suit my situation.

And then I'll ask you, as a top gun, some more quesstions <g>.

Pat
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top