Storing formatted text in a variable and pasting it back.

M

marzolian

I sometimes need to use a macro to temporarily move footnotes from
their actual location. Here's the current version:

http://techlanguage.com/tips/MoveFootnotesToEnd.txt

The routine "MoveFootnotesToEnd" copies each footnote text into a
string array, sets a bookmark at the location of the footnote, and
deletes the footnote. It then moves to the very end of the document
and creates a table. Finally, it pastes each footnote into the table.

A second macro restores each footnote to its original position.

My problem is, this version strips all the formatting from each
footnote.

To fix it, my first thought was, instead storing the text in a string,
I could use some other variable type. In the assignment step, these
statements do put the proper value into the variable:

ReDim FootnoteText(Q) As Variant

Set FootnoteText(i) = Fnote.Range.FormattedText

However, I can't get VB to paste or type the formatted text into the
table cell. This statement was used to test the location:

Selection.Tables(1).Cell(i + 1, Q).Range.Text = "xxx"

xxx shows up in the correct table cell. But this step produces
nothing:

Selection.Tables(1).Cell(i + 1, Q).Range.FormattedText =
FootnoteText(i).FormattedText

The VB editor tells me that FootnoteText(i) = "" (empty string) when
it comes to this step.

Any suggestions? Thanks.

Steven Marzuola
(e-mail address removed)
(delete dashes and invalid)
 
J

Jean-Guy Marcil

marzolian was telling us:
marzolian nous racontait que :
I sometimes need to use a macro to temporarily move footnotes from
their actual location. Here's the current version:

http://techlanguage.com/tips/MoveFootnotesToEnd.txt

The routine "MoveFootnotesToEnd" copies each footnote text into a
string array, sets a bookmark at the location of the footnote, and
deletes the footnote. It then moves to the very end of the document
and creates a table. Finally, it pastes each footnote into the table.

A second macro restores each footnote to its original position.

My problem is, this version strips all the formatting from each
footnote.

To fix it, my first thought was, instead storing the text in a string,
I could use some other variable type. In the assignment step, these
statements do put the proper value into the variable:

ReDim FootnoteText(Q) As Variant

Set FootnoteText(i) = Fnote.Range.FormattedText

However, I can't get VB to paste or type the formatted text into the
table cell. This statement was used to test the location:

Selection.Tables(1).Cell(i + 1, Q).Range.Text = "xxx"

xxx shows up in the correct table cell. But this step produces
nothing:

Selection.Tables(1).Cell(i + 1, Q).Range.FormattedText =
FootnoteText(i).FormattedText

The VB editor tells me that FootnoteText(i) = "" (empty string) when
it comes to this step.

Any suggestions? Thanks.

Steven Marzuola
(e-mail address removed)
(delete dashes and invalid)

Could we see the full relevant code instead of excerpts?

--

Salut!
_______________________________________
Jean-Guy Marcil - Word MVP
(e-mail address removed)
Word MVP site: http://www.word.mvps.org
 
J

Jean-Guy Marcil

marzolian was telling us:
marzolian nous racontait que :
This is the old version, that works, but strips all formatting:

http://techlanguage.com/tips/MoveFootnotesToEnd.txt

I'm working on a version that preserves the formatting, but it doesn't
work:

http://www.techlanguage.com/tips/NewMoveFootnotes.txt

There are lots of problems with your code.

1) You should not use End, it is not necessary in VBA, Just use "Exit Sub"
2) Only use the Selection object when you absolutely need to, in this case
it is absolutely unnecessary!
3) Use objects when manipulating different area of a document, like a table
and footnotes in this case
4) You tried something like:
Selection.FormattedText = FootnoteText(i).FormattedText
FootnoteText(i) is a variant Array, you can not append Word VBA
property to it. The compiler will try to interpret it and will try to read
"FootnoteText(i)" as some range and fails.
5) Selection.TypeText Text:=FootnoteMark(i) is unclear as to what it is
supposed to do. FootnoteMark(i) is not an actual printable character.
6) The way your statements are put together, Selection.TypeText
Text:="MoveFootnotesToEnd" inserts the text in the first cell of the table.
Is that intentional?

Here is a revised version that corrects all those problems. It will get you
started...

'_______________________________________
Sub MoveFootnotesToEnd()

Dim i As Long
Dim Q As Long

Dim tbleFootNotes As Table
Dim rgeTbl As Range
Dim rgeRef As Range

If ActiveDocument.Footnotes.Count = 0 Then
Exit Sub
Else
Q = ActiveDocument.Footnotes.Count
End If

'Set up the table right away
Set rgeTbl = ActiveDocument.Range

With rgeTbl
.InsertParagraphAfter
.Collapse wdCollapseEnd
.Style = ActiveDocument.Styles(wdStyleFootnoteText)
.InsertAfter "MoveFootnotesToEnd"
.InsertParagraphAfter
.Collapse wdCollapseEnd
End With

Set tbleFootNotes = rgeTbl.Tables.Add(Range:=rgeTbl, NumRows:=Q, _
NumColumns:=2, DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=wdAutoFitFixed)

'Transfer and delete footnotes
i = 1

Do While ActiveDocument.Footnotes.Count > 0
With tbleFootNotes
.Cell(i, 1).Range.Text = "Footnote # " & i
.Cell(i, 2).Range.FormattedText =
ActiveDocument.Footnotes(1).Range.FormattedText
End With
Set rgeRef = ActiveDocument.Footnotes(1).Reference
ActiveDocument.Footnotes(1).Delete
ActiveDocument.Bookmarks.Add Range:=rgeRef, Name:="xxFootnote" & i
i = i + 1
Loop

End Sub
'_______________________________________

--

Salut!
_______________________________________
Jean-Guy Marcil - Word MVP
(e-mail address removed)
Word MVP site: http://www.word.mvps.org
 
M

marzolian

marzolian was telling us:
marzolian nous racontait que :




There are lots of problems with your code.

1) You should not use End, it is not necessary in VBA, Just use "Exit Sub"
2) Only use the Selection object when you absolutely need to, in this case
it is absolutely unnecessary!
3) Use objects when manipulating different area of a document, like a table
and footnotes in this case
4) You tried something like:
Selection.FormattedText = FootnoteText(i).FormattedText
FootnoteText(i) is a variant Array, you can not append Word VBA
property to it. The compiler will try to interpret it and will try to read
"FootnoteText(i)" as some range and fails.
5) Selection.TypeText Text:=FootnoteMark(i) is unclear as to what it is
supposed to do. FootnoteMark(i) is not an actual printable character.
6) The way your statements are put together, Selection.TypeText
Text:="MoveFootnotesToEnd" inserts the text in the first cell of the table.
Is that intentional?

Here is a revised version that corrects all those problems. It will get you
started...

'_______________________________________
Sub MoveFootnotesToEnd()

Dim i As Long
Dim Q As Long

Dim tbleFootNotes As Table
Dim rgeTbl As Range
Dim rgeRef As Range

If ActiveDocument.Footnotes.Count = 0 Then
Exit Sub
Else
Q = ActiveDocument.Footnotes.Count
End If

'Set up the table right away
Set rgeTbl = ActiveDocument.Range

With rgeTbl
.InsertParagraphAfter
.Collapse wdCollapseEnd
.Style = ActiveDocument.Styles(wdStyleFootnoteText)
.InsertAfter "MoveFootnotesToEnd"
.InsertParagraphAfter
.Collapse wdCollapseEnd
End With

Set tbleFootNotes = rgeTbl.Tables.Add(Range:=rgeTbl, NumRows:=Q, _
NumColumns:=2, DefaultTableBehavior:=wdWord9TableBehavior, _
AutoFitBehavior:=wdAutoFitFixed)

'Transfer and delete footnotes
i = 1

Do While ActiveDocument.Footnotes.Count > 0
With tbleFootNotes
.Cell(i, 1).Range.Text = "Footnote # " & i
.Cell(i, 2).Range.FormattedText =
ActiveDocument.Footnotes(1).Range.FormattedText
End With
Set rgeRef = ActiveDocument.Footnotes(1).Reference
ActiveDocument.Footnotes(1).Delete
ActiveDocument.Bookmarks.Add Range:=rgeRef, Name:="xxFootnote" & i
i = i + 1
Loop

End Sub


Jean-Guy,

I knew there were problems, it was very quick and dirty. This step is
intentional.

Selection.TypeText Text:="MoveFootnotesToEnd"

I use the presence of this text in the reverse function, the one that
restores the footnotes to their original locations in the text. Also,
to find the table that includes these footnotes. That function will
have to be revised as well.

However, before I could implement any solution for now, I needed to
get started on my project (It's a translation of about 14,000
words). But as soon as it's finished, I'll try out your solution.
Thanks!

Steven
 
J

Jean-Guy Marcil

marzolian was telling us:
marzolian nous racontait que :
I knew there were problems, it was very quick and dirty. This step is
intentional.

Selection.TypeText Text:="MoveFootnotesToEnd"

I use the presence of this text in the reverse function, the one that
restores the footnotes to their original locations in the text. Also,
to find the table that includes these footnotes. That function will
have to be revised as well.

What I meant was that I have no problem with inserting this in the document
(I did insert it in my code, but just before the table). But the problem in
your code is that you insert a table with a number of rows equal to the
number of footnotes. Then, you insert this text in the first row. When I ran
your code as you posted it in the link you provided, the code ended up
missing a row...

So either you create a table with a number of rows equal to the number of
footnotes plus one, or the reverse function locates the table by locating
this text and then grabbing the following table.

--

Salut!
_______________________________________
Jean-Guy Marcil - Word MVP
(e-mail address removed)
Word MVP site: http://www.word.mvps.org
 
T

Tom Bresson

Jean-Guy Marcil said:
marzolian was telling us:
marzolian nous racontait que :


What I meant was that I have no problem with inserting this in the document
(I did insert it in my code, but just before the table). But the problem in
your code is that you insert a table with a number of rows equal to the
number of footnotes. Then, you insert this text in the first row. When I ran
your code as you posted it in the link you provided, the code ended up
missing a row...

So either you create a table with a number of rows equal to the number of
footnotes plus one, or the reverse function locates the table by locating
this text and then grabbing the following table.

--

Salut!
_______________________________________
Jean-Guy Marcil - Word MVP
(e-mail address removed)
Word MVP site: http://www.word.mvps.org


Hello,

I am having a problem with something very similar to the title of the thread.

I have a document template that I need to hold a few generic incomplete
sections of (While retaining the formatting of the text), so that they can be
duplicated and filled in as my VBA code runs.

Essentially, I want to have a sub that takes a range of text and inserts it
in an array or collection object, preserving formatting. Then I need another
sub to be able to retrieve the "Formatted Text" Object and put the text into
Word.

I am relatively new to the Office VBA types and functions, and I am learning
as I go, but this has stumped me for more than a few hours.

Here is my code thus far:


<code>
'The effective use of this class will be document specific.
'In theory, this should be the only file that needs changed to modify from
document to document
'when the other document is fairly similar to this one.


Private tagFirstLevel, tagSecondLevel, tagThirdLevel, tagEndTag As String

Private collectionOfFormattedText As Collection


Sub initialize()

tagFirstLevel = "<Functional Area>"
tagSecondLevel = "<TEST DESCRIPTION CATEGORY>"
tagThirdLevel = "<Individual Test Description>"
tagEndTag = "<End_of_Test>"

Set collectionOfFormattedText = New Collection

End Sub

Sub findFirstSection()
End Sub

Sub processFolder()
End Sub


Sub processTestSet()
End Sub


Sub processTest()
End Sub


Sub processTestRun()
End Sub

Sub setSelectionRange(ByVal startingString As String, ByVal endingString As
String)

Dim selectionStart As Integer
Dim selectionEnd As Integer

Selection.Find.ClearFormatting
With Selection.Find
.Text = startingString
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If .Found Then
selectionStart = Selection.Start
End If
End With

Selection.Find.ClearFormatting
With Selection.Find
.Text = endingString
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If .Found Then
selectionEnd = Selection.Start
End If
End With

Selection.Start = selectionStart
Selection.End = selectionEnd

End Sub

Sub insertSelectionIntoFormattedTextCollection()
Dim temp As Variant
Set temp = Selection.FormattedText

'This was to test if the text came out of the Variant ok,
'AND IT DOES!
'Selection.Range.FormattedText = temp

collectionOfFormattedText.Add (temp)


End Sub

Sub insertFormattedTextIntoSelection(indexOfFormattedText As Integer)

Selection.FormattedText =
collectionOfFormattedText.Item(indexOfFormattedText)

End Sub

Sub test()

Call DocParser.initialize

Call setSelectionRange(tagFirstLevel, tagSecondLevel)
Call insertSelectionIntoFormattedTextCollection

Call setSelectionRange(tagSecondLevel, tagThirdLevel)
Call insertSelectionIntoFormattedTextCollection

Call setSelectionRange(tagThirdLevel, tagEndTag)
Call insertSelectionIntoFormattedTextCollection

Call insertFormattedTextIntoSelection(1)
Call insertFormattedTextIntoSelection(2)
Call insertFormattedTextIntoSelection(3)
Call insertFormattedTextIntoSelection(3)
Call insertFormattedTextIntoSelection(3)

End Sub
</code>

Any help at all would be very much appreciated!

Thank you all,

-Tom
 
J

Jean-Guy Marcil

Tom Bresson was telling us:
Tom Bresson nous racontait que :
Hello,

I am having a problem with something very similar to the title of the
thread.

I have a document template that I need to hold a few generic
incomplete sections of (While retaining the formatting of the text),
so that they can be duplicated and filled in as my VBA code runs.

Essentially, I want to have a sub that takes a range of text and
inserts it in an array or collection object, preserving formatting.
Then I need another sub to be able to retrieve the "Formatted Text"
Object and put the text into Word.

I am relatively new to the Office VBA types and functions, and I am
learning as I go, but this has stumped me for more than a few hours.

Here is my code thus far:


<code>
'The effective use of this class will be document specific.
'In theory, this should be the only file that needs changed to modify
from document to document
'when the other document is fairly similar to this one.


Private tagFirstLevel, tagSecondLevel, tagThirdLevel, tagEndTag As
String

Here, only tagEndTag is a String, all other are Variant.
Private collectionOfFormattedText As Collection


Sub initialize()

tagFirstLevel = "<Functional Area>"
tagSecondLevel = "<TEST DESCRIPTION CATEGORY>"
tagThirdLevel = "<Individual Test Description>"
tagEndTag = "<End_of_Test>"

Set collectionOfFormattedText = New Collection

End Sub

Sub findFirstSection()
End Sub

Sub processFolder()
End Sub


Sub processTestSet()
End Sub


Sub processTest()
End Sub


Sub processTestRun()
End Sub

Sub setSelectionRange(ByVal startingString As String, ByVal
endingString As String)

Dim selectionStart As Integer
Dim selectionEnd As Integer

Range (or Selection) Start and End properties are defined in VBA as Long,
not Integer.
So, here, the compiler as to do unnecessary type conversion.

By the way, Integer is no longer the base numeric unit, Long is.
Even if you use Integer, the compiler converts them to Long because the
smallest memory unit is a equivalent to a Long.

Selection.Find.ClearFormatting
With Selection.Find
.Text = startingString
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If .Found Then
selectionStart = Selection.Start
End If
End With

Selection.Find.ClearFormatting
With Selection.Find
.Text = endingString
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If .Found Then
selectionEnd = Selection.Start
End If
End With

Selection.Start = selectionStart
Selection.End = selectionEnd

End Sub

It would probably be better to use a Range object instead of defining a
Selection object.
Sub insertSelectionIntoFormattedTextCollection()
Dim temp As Variant
Set temp = Selection.FormattedText

'This was to test if the text came out of the Variant ok,
'AND IT DOES!
'Selection.Range.FormattedText = temp

It does, but not formatted, right?
collectionOfFormattedText.Add (temp)


End Sub

Sub insertFormattedTextIntoSelection(indexOfFormattedText As Integer)

Use a Long instead of an Integer
Selection.FormattedText =
collectionOfFormattedText.Item(indexOfFormattedText)

Selection.FormattedText expects a Range object, you are feeding it a
Variant, as is it will not work.
You could use:
Selection.TypeText collectionOfFormattedText.Item(indexOfFormattedText)
But this will not return formatted text, which it does not matter anyway
because the Collection does not contain formatted text.

End Sub

Sub test()

Call DocParser.initialize

Call setSelectionRange(tagFirstLevel, tagSecondLevel)
Call insertSelectionIntoFormattedTextCollection

Call setSelectionRange(tagSecondLevel, tagThirdLevel)
Call insertSelectionIntoFormattedTextCollection

Call setSelectionRange(tagThirdLevel, tagEndTag)
Call insertSelectionIntoFormattedTextCollection

Call insertFormattedTextIntoSelection(1)
Call insertFormattedTextIntoSelection(2)
Call insertFormattedTextIntoSelection(3)
Call insertFormattedTextIntoSelection(3)
Call insertFormattedTextIntoSelection(3)

As is, by the time you get to the first Call
insertFormattedTextIntoSelection, yourt selection is ocated at teh lst item
that was found when setSelectionRange was called.
So, in effect, yu are inserting text over the lst found items...

THis is why I suggested using range objects instead.
End Sub
</code>

I am afraid that as long as you are going to work with any type of
variables, you will not succeed as variables cannot hold formatting
information, unless there is some type of RichText variable that I am not
aware of.

What you could do is create an invisible document (starting with Word XP, I
believe) and store the ranges there when you find them, then when you are
done, get them back.

Or, if you are selecting ranges of text and then, in the same code run,
copying those range elsewhere in the document, you do not need a collection
or a secondary document, copy those bits of text as you find them.

--

Salut!
_______________________________________
Jean-Guy Marcil - Word MVP
(e-mail address removed)
Word MVP site: http://www.word.mvps.org
 
T

Tom Bresson

Thank you for the help Jean-Guy Marcil,

I found creating, using and removing autotext entries programically seems to
allow me to be able to easily insert formatted text into a document. It
essentially boils down to:

Select a range, create a known autotext entry (which can preserve
formatting) in the Normal template, use the autotext entry, then delete the
autotext entry when done.

There is plenty of documentation of autotext entries on the MSDN site. I am
very surprised that Microsoft did not include a variable type to store
formatted text. I would think that would be very desired behavior for a
language that should be able to help automate documents.

I hope this helps anyone who happens to stumble upon this thread, via
Google, like I did.

Thanks again!

-Tom
 

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