Fields are nested too deeply in a simple macros
|
|
Thread rating:  |
redkaa@officeformac.com - 24 Jul 2008 10:58 GMT 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...
John McGhie - 24 Jul 2008 11:48 GMT 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
On 24/07/08 7:28 PM, in article 59b5505b.-1@webcrossing.caR9absDaxw,
> Version: 2004 > Operating System: Mac OS X 10.4 (Tiger) [quoted text clipped - 26 lines] > ÔÂÙËÍÒ? or sometimes just question marks... Something goes wrong with > the encoding...
 Signature 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:john@mcghie.name
redkaa@officeformac.com - 24 Jul 2008 12:17 GMT > 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?
John McGhie - 25 Jul 2008 10:29 GMT 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
On 24/07/08 8:47 PM, in article 59b5505b.1@webcrossing.caR9absDaxw,
>> 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?
 Signature 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:john@mcghie.name
Serge - 26 Jul 2008 11:30 GMT 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...
Serge - 26 Jul 2008 12:30 GMT 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???
John McGhie - 26 Jul 2008 13:11 GMT 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
On 26/07/08 9:00 PM, in article 59b5505b.4@webcrossing.caR9absDaxw, "Serge"
> Actually, this code could be presented as following: > For i = 1 To ActiveDocument.Paragraphs.Count [quoted text clipped - 4 lines] > As far as I get, out of each paragraph in the document I make a hyperlink. > Where do I create any nests???
 Signature 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:john@mcghie.name
Serge - 26 Jul 2008 15:50 GMT 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?
John McGhie - 29 Jul 2008 07:25 GMT Hi Serge:
On 27/07/08 12:50 AM, in article 59b5505b.6@webcrossing.caR9absDaxw, "Serge"
> John, I used your code - with the same result. It runs a mistake at 20-th > iteration. [quoted text clipped - 11 lines] > 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
 Signature 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:john@mcghie.name
Serge - 29 Jul 2008 11:53 GMT 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?
John McGhie - 30 Jul 2008 14:44 GMT 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
On 29/07/08 8:53 PM, in article 59b5505b.8@webcrossing.caR9absDaxw, "Serge"
> Hello, John! > As for deleting hyperlinks - it's now clear for me. Probably, it's because I [quoted text clipped - 7 lines] > paragraph?). Now I start hesitating - may be it was my mistake that I mix two > those?
 Signature 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:john@mcghie.name
Serge - 30 Jul 2008 15:06 GMT .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...
John McGhie - 31 Jul 2008 11:02 GMT 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
 Signature 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:john@mcghie.name
|
|
|