Fields are nested too deeply in a simple macros

R

redkaa

Version: 2004
Operating System: Mac OS X 10.4 (Tiger)
Processor: Intel

Hello!
I have a document, containing 30-40 lines of numbers (say, 30-40 paragraphs). I'd like to make hyperlinks of them.
I use the following code
Sub Compile_Menu()
Dim f As Range = 1 Set f = Selection.Range
n = f.Paragraphs.Count
m = InputBox("Cumon!", "Type in da title", "mylist")
For i = 1 To n
s = f.Paragraphs(i)
ActiveDocument.Hyperlinks.Add Anchor:=s, SubAddress:=m + CStr(i)
Next i
End Sub
But it results in an error "Fields are nested too deeply" when processing the 20-th line of the file. What am I doing wrong?

P.S. Is it possible to use the local layout in the macros? umlauts? Chinese characters? At least when I tried Russian:
m = InputBox("Просыпайся!", "какой будем использовать префикс?", "mylist")
I got instead èÓÒ˚Ô‡ÈÒfl! ä‡ÍÓÈ ·Û‰ÂÏ ËÒÔÓθÁÓ‚‡Ú¸ ÔÂÙËÍÒ? or sometimes just question marks... Something goes wrong with the encoding...
 
J

John McGhie

You are not moving your selection.range inside the loop, so you are placing
each field inside the previous one, until they are indeed too deeply nested
:)

No, it is not generally possible to use Unicode in this version of VBA.
Stick to ANSI :)

Cheers


Version: 2004
Operating System: Mac OS X 10.4 (Tiger)
Processor: Intel

Hello!
I have a document, containing 30-40 lines of numbers (say, 30-40 paragraphs).
I'd like to make hyperlinks of them.
I use the following code
Sub Compile_Menu()
Dim f As Range = 1 Set f = Selection.Range
n = f.Paragraphs.Count
m = InputBox("Cumon!", "Type in da title", "mylist")
For i = 1 To n
s = f.Paragraphs(i)
ActiveDocument.Hyperlinks.Add Anchor:=s, SubAddress:=m + CStr(i)
Next i
End Sub
But it results in an error "Fields are nested too deeply" when processing the
20-th line of the file. What am I doing wrong?

P.S. Is it possible to use the local layout in the macros? umlauts? Chinese
characters? At least when I tried Russian:
m =
InputBox("Просыпайс&#110
3;!", "какой будем
использоват&
#1100; префикс?", "mylist")
I got instead èÓÒ˚Ô‡ÈÒfl! ä‡ÍÓÈ ·Û‰ÂÏ ËÒÔÓθÁÓ‚‡Ú¸
ÔÂÙËÍÒ? or sometimes just question marks... Something goes wrong with
the encoding...

--
Don't wait for your answer, click here: http://www.word.mvps.org/

Please reply in the group. Please do NOT email me unless I ask you to.

John McGhie, Microsoft MVP, Word and Word:Mac
Sydney, Australia. mailto:[email protected]
 
R

redkaa

You are not moving your selection.range inside the loop, so you are placing
each field inside the previous one, until they are indeed too deeply nested
:)

so, what's the missed line then? I did not get it :-(
as for ANSI - Does it mean, I can't add a Russian string to my document?
 
J

John McGhie

s = f.Paragraphs(i) -- that should be
s = f.Paragraphs(i).range

And then after you add the hyperlink, you need to move "s" to the NEXT
paragraph before the next iteration of the loop.

You can add a Russian string, but you will have to set it up using CHr and
the Unicode numbers of the characters. As strings, VBA can handle only the
ANSI character set.

Cheers


so, what's the missed line then? I did not get it :-(
as for ANSI - Does it mean, I can't add a Russian string to my document?

--
Don't wait for your answer, click here: http://www.word.mvps.org/

Please reply in the group. Please do NOT email me unless I ask you to.

John McGhie, Microsoft MVP, Word and Word:Mac
Sydney, Australia. mailto:[email protected]
 
S

Serge

Thank you for your answer, John, but there is still something I did not understand.
okay, let's forget about the Russian language for some time.
as for the first issue:
when I do
s = f.Paragraphs(i).range always get an "Object required" run-time error at the next line: ActiveDocument.Hyperlinks.Add anchor:=s, SubAddress:=m + CStr(i)
Besides, I can't catch, why I need to do s.NEXT (or whatever else) when I have an i index, pointing to the desired paragraph in the loop. Probably, that's why I can't understand where it becomes looped... :-(

Meanwhile, I've got another issue in the other script, which parses the big text taking the first three lines after each manual page break sign and pasting them to another document. For some reason it skips some of the sections. I did not figure out why.. :-(
But first, I'll have to have extensive testing to find out the reasons...
 
S

Serge

Actually, this code could be presented as following:
For i = 1 To ActiveDocument.Paragraphs.Count
ActiveDocument.Hyperlinks.Add anchor:=ActiveDocument.Paragraphs(i).Range, SubAddress:=CStr(i)
Next i

As far as I get, out of each paragraph in the document I make a hyperlink. Where do I create any nests???
 
J

John McGhie

Hi Sere:

Sorry, you're using undeclared variables so I can't really figure out what
is going on.

What do you actually have in variable "s"? Is it the paragraph, the
selection, or the range?

As far as I can remember, if you set s = to a selection, you will extend the
selection each time. But the hyperlink will anchor to the beginning of the
range, so I think that each time, you are inserting the hyperlink inside the
previous one.

It's a bit hard for me to see, from your code.

I would probably have written something like:

For each aPara in Selection.paragraphs
Set s = aPara.range
ActiveDocument.Hyperlinks.Add Anchor:=s, SubAddress:=m + s.text
Next aPara

That explicitly redefines the range in s for each iteration.

Sorry: I am at an airport right now, I can't test this properly. But I
think you are dropping your hyperlink into the same place each time.

This "could" be because you're going to quick for it. Recall that when you
add the hyperlink, you add it to the DOCUMENT collection? So Word must
recompile the collection each add. If you go to quick, you will get a
series of undefined errors.

Sometimes, the only way to overcome these is to add a document.save every
tenth iteration or so, which forces Word to redefine its pointers in all the
collections.

Hope this helps

Actually, this code could be presented as following:
For i = 1 To ActiveDocument.Paragraphs.Count
ActiveDocument.Hyperlinks.Add anchor:=ActiveDocument.Paragraphs(i).Range,
SubAddress:=CStr(i)
Next i

As far as I get, out of each paragraph in the document I make a hyperlink.
Where do I create any nests???

--
Don't wait for your answer, click here: http://www.word.mvps.org/

Please reply in the group. Please do NOT email me unless I ask you to.

John McGhie, Microsoft MVP, Word and Word:Mac
Sydney, Australia. mailto:[email protected]
 
S

Serge

John, I used your code - with the same result. It runs a mistake at 20-th iteration.
What do you mean by 'to quick for it'?
Besides, I inserted ActiveDocument.Save inside the loop - the same result.
The next issue is quite bizarre for me! May be that could help us define the problem?
I was tired of doing 'command+z' to undo all those iterations to start the script from the very beginning. So, I used the following script, which was supposed to remove all the hyperlinks:
Sub RemoveHyperlinks()
Dim Hyp As Hyperlink
For Each Hyp In ActiveDocument.Hyperlinks
Hyp.Delete
Next
End Sub

To my surprise, I had to run it several times, as it did not remove all the links from the first time. To be exact:
I have a file containing 24 lines with numbers from 1 to 24.
When I run the first script to create hyperlinks, I have to click "OK" on my error message box (fields are nested too deeply) four times. In the end I have a file with 24 lines of numerated hyperlinks (from 1 to 24, each line unique) in blue.
When I run the other script to remove the hyperlinks, the first time - all the lines seem to be simple black text (as if there were no hyperlinks). But when I point a mouse at the lines, I figure out that
1) only 24th line is simple text, others are still hyperlinks (although black, not blue)
2)!!! The first line is hyperlinked as it was - 'doc1'. But the second line and the third one are linked to 'doc3', the fourth and the fifth one are linked to 'doc5', the sixth and the seventh - to 'doc7' and so on. 22-d and 23-d lines - to 'doc23', with 24-th line, as I said earlier - simple text.

Then!!! I run this script again, to remove these masked hyperlinks.
Now, the first line is still linked to 'doc1',
the next four lines are linked to 'doc5', the next four lines (6th to 9th) are linked to 'doc9', the next four - to 'doc13' and so on, ending with 18-21 to 'doc21' and the rest three lines being plain text.
I run it again, and I get the following:
the first line remains the same - 'doc1'
the lines from 2 to 9 are linked to 'doc9', the lines from 10 to 17 are linked to 'doc17', lines 18 to 24 - plain text.
I run the script once more time: now the first 9 lines are linked to 'doc9', lines 10-24 are plain text.
Finally, I run the script for the last time to remove hyperlinks.
What could cause it to behave like that?
What's the structure of hyperlinks?
 
J

John McGhie

Hi Serge:

John, I used your code - with the same result. It runs a mistake at 20-th
iteration.
What do you mean by 'to quick for it'?
Besides, I inserted ActiveDocument.Save inside the loop - the same result.
The next issue is quite bizarre for me! May be that could help us define the
problem?
I was tired of doing 'command+z' to undo all those iterations to start the
script from the very beginning. So, I used the following script, which was
supposed to remove all the hyperlinks:
Sub RemoveHyperlinks()
Dim Hyp As Hyperlink
For Each Hyp In ActiveDocument.Hyperlinks
Hyp.Delete
Next
End Sub

Yeah, on each iteration that will take out only every "second" hyperlink in
the document. That's a well-known (but irritating...) feature of dynamic
collections.

Each time you delete a hyperlink, the collection re-numbers. But your
control variable does not. So on the first iteration, Hyperlink 1 is
deleted, Hyperlink 2 becomes "1" and "Hyp" becomes "2".

On the next iteration, the hyperlink that was "3" gets deleted. And so
on...

Try
For I = activedocument.hyperlinks.count to 1 step -1
Hyp.Delete
Next
I have a file containing 24 lines with numbers from 1 to 24.

I do hope that by "lines" you mean "paragraphs"? If not, there's your
problem. The hyperlink is anchored to a text range. Unless you place that
text range somewhere else, it will be at the beginning of the paragraph. If
your document literally does have lines instead of paragraphs, all
hyperlinks are being anchored at the beginning of the paragraph.

I think what is happening is that each time you insert a hyperlink, Word is
expanding the range to encompass the new hyperlink.

So you need to re-construct your loop to reposition the range and then
collapse it, before you insert your hyperlink.

To find out if this is what is happening, set a break-point inside your
loop, then "step" the loop through one iteration at a time, and look to see
where the range lands each time.
What could cause it to behave like that?
What's the structure of hyperlinks?

I think this is normal. Whenever you insert an object in VBA, it either
replaces the range you specified, or expands to encompass the range you
specified.

Then when you insert another, the range expands to encompass both. And so
on...

So you need to position your range, the collapse the range, then insert the
hyperlink, then move the range forward to the next paragraph.

When you "Move" a range, it should automatically collapse to an insertion
point. If instead you "MoveEnd" or "MoveStart" it expands.

If you like, email me your test document and your code, and I will see if I
have time to have a look at this for you.

Hope this helps

--
Don't wait for your answer, click here: http://www.word.mvps.org/

Please reply in the group. Please do NOT email me unless I ask you to.

John McGhie, Microsoft MVP, Word and Word:Mac
Sydney, Australia. mailto:[email protected]
 
S

Serge

Hello, John!
As for deleting hyperlinks - it's now clear for me. Probably, it's because I do not know the way this 'for each item in collection do' construction works. I'll use your construction then.
By lines I mean paragraphs. That's what stumbles me.
Sorry to say, I do not know how to set up a break-point and more important - how to see the state of the range.
I'd send you my test file and the code, but I don't know what your email is.
By the way, is there a difference between end of line and end of the paragraph?). Now I start hesitating - may be it was my mistake that I mix two those?
 
J

John McGhie

Hi Serge:

It's not "For each..." that you are having difficulty with, that works the
way you would expect it to.

It's "collections" you are having problems with. Collections
populate/depopulate dynamically. In this case, you are depopulating the
Hyperlinks collection by removing items from it.

For Each ... Next is simply a shorthand way of writing what you were
writing. The compiler takes care of the control variables for you.

But if you have items 1 to 10 in a collection... And you delete item 1, the
next item in the collection is instantly renumbered from 2 to 1. But your
loop then deletes "2" -- the item which WAS "3". Now, "3" becomes "2", but
your loop then deletes "3" -- the item which was "4" .... And so on. :)

To fix this, with dynamic collections such as Hyperlinks, you must work
BACKWARDS "up" the collection, otherwise each time you delete one, the
collection re-numbers and you end up deleting every second item.

To set a break-point, click to the left of the line of code until a brown
spot appears. Execution will stop at that point on each iteration.

If you don't know my email address, you didn't read any of my posts: it has
been in the signature of every one of them :)

Yes, there is all the difference in the world between an end of line and an
end of paragraph. A line is a string of text. A Paragraph is a container
object that contains not only strings of text, but pointers to all the
properties that pertain to that text.

Look up the Word Document Object Model in the Help: you need to know this to
write VBA. It does not appear unless you call the Help from the VBA Editor
(which is a separate application).

Cheers

Hello, John!
As for deleting hyperlinks - it's now clear for me. Probably, it's because I
do not know the way this 'for each item in collection do' construction works.
I'll use your construction then.
By lines I mean paragraphs. That's what stumbles me.
Sorry to say, I do not know how to set up a break-point and more important -
how to see the state of the range.
I'd send you my test file and the code, but I don't know what your email is.
By the way, is there a difference between end of line and end of the
paragraph?). Now I start hesitating - may be it was my mistake that I mix two
those?

--
Don't wait for your answer, click here: http://www.word.mvps.org/

Please reply in the group. Please do NOT email me unless I ask you to.

John McGhie, Microsoft MVP, Word and Word:Mac
Sydney, Australia. mailto:[email protected]
 
S

Serge

..Name. is a strange TLD, isn't i?
As for the collections issue - I got it from the first time, thank you for further explanations anyway.
As for the second issue, yep, they were paragraphs. At least, msgbox ActiveDocument.Paragrpahs.count each time was equal to the number of my lines in the test document. When I changed for another symbol (shift+return) - it became the single paragraph with a single link, and it worked fine :)
I coped with the breakpoints, but I do not know how to check the value of my objects and variables...
 
J

John McGhie

Hey Serge:

The .name top-level domain is no stranger than .biz or .gov -- Just more
exclusive :) (And much less likely to attract spam...)

For all the lucky listeners that have been following along, here's the
outcome:

* * * * * *

This problem was very difficult to solve because it was being "hidden" by
coding techniques that we all do because it seems that they save time, but
they come back to bite you later when you are trying to debug.

Always include the Compiler Directive "Option Explicit" at the top of each
module, so that the compiler will warn you if you have any undeclared
variables. This is a useful check against spelling errors and type
mis-matches.

Now: A "range" includes the whole of an object, including its container. In
the case of a paragraph, the container is the paragraph mark, and the range
includes it. If you do not turn on your paragraph marks when doing
development work, you cannot see what you are doing. Stumbling around in
the dark may be exciting, but the bruised shins get old after a while :)

So when you anchored like this: anchor:=ActiveDocument.Paragraphs(i).Range,
you were anchoring to a range that ended immediately before the next
paragraph. When you then anchored to the next paragraph, your anchor range
began inside the previous range. So you ended up with 20 hyperlinks inside
each other.

In the code below, note that I first return the range of the paragraph I
want, and then I shrink the range so it cannot join the one following it. I
have done it two ways: the easiest way is to simply collapse the range to an
insertion point. However, if you want to include the text of the paragraph
in the hyperlink hotspot, you need to do it the second way: shrink the range
by one character to get the paragraph mark out of it.

I can understand how tempting it is to take shortcuts. But through bitter
experience, I have learned not to do it. I re-learn this lesson almost
every day... Notice how I re-named the variables to something
self-explanatory? This is so I can work out what the {naughty word}s are
doing when the code blows up!! Using short variable names just makes your
code hard to read: the compiler doesn¹t care, it reduces them all to binary
integers anyway. So use something self-explanatory, so you can see what you
are doing!!

Be careful to avoid variable names the same as keywords or VBA commands, or
you will get yourself totally confused!

Hope this helps


Option Explicit

Sub Compile_Menu1()
Dim thisPar As Range ' One Dim per line so you can see what you are doing
Dim Sel As Range ' No undefined variables, too accident-prone
Dim i As Long ' Loops control variables are longs (compiler's native binary
word) for best speed
Dim docName As String

Set Sel = Selection.Range
docName = Left(ActiveDocument.Name, 3)
'MsgBox n

' This code sets the hyperlink at the beginning of each para
'For i = 1 To Sel.Paragraphs.Count ' Initialise i here
' Set thisPar = Sel.Paragraphs(i).Range ' Choose one para
' thisPar.Collapse direction:=wdCollapseStart ' Collapse range to
insertion point
' ActiveDocument.Hyperlinks.Add _
' Anchor:=thisPar, _
' SubAddress:=docName + CStr(i)
'Next i

' If you want to include the text in the hyperlink,
' you need to contract the range instead of collapsing it
For i = 1 To Sel.Paragraphs.Count ' Initialise i here
Set thisPar = Sel.Paragraphs(i).Range ' Choose one para
thisPar.MoveEnd unit:=wdCharacter, Count:=-1 ' back one char
ActiveDocument.Hyperlinks.Add _
Anchor:=thisPar, _
SubAddress:=docName + CStr(i)
Next i

Selection.ClearFormatting ' Don't do this disgusting direct formatting
Selection.Font.Name = "Arial" ' Define a style and use it!!
End Sub

--
Don't wait for your answer, click here: http://www.word.mvps.org/

Please reply in the group. Please do NOT email me unless I ask you to.

John McGhie, Microsoft MVP, Word and Word:Mac
Sydney, Australia. mailto:[email protected]
 

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