MS Office Forum / Word / Programming / April 2005
Display same screen after macro executes
|
|
Thread rating:  |
Alan F - 23 Mar 2005 15:25 GMT Can anybody please help me?
I have written a macro that operates on a collection in a long document (300 pages). (deletes all index entry marks)
I have used the screen refresh = false so that the document does not scroll during execution.
The trouble is that on completion the displayed page "jumps" so that the the line the cursor is at scrolls to the top of the screen. I have used the range object to at least keep the same page displayed. I would like the screen/page position to remain unchanged.
Any suggestions will be most welcome!
Thanks
Alan F.
Cindy M -WordMVP- - 27 Mar 2005 17:05 GMT Hi Alan,
Hard to offer any advice without knowing HOW you're doing this? Find/Replace, or looping the Fields collection, or something else?
> I have written a macro that operates on a collection in a long document (300 > pages). (deletes all index entry marks) [quoted text clipped - 6 lines] > I have used the range object to at least keep the same page displayed. > I would like the screen/page position to remain unchanged. Cindy Meister INTER-Solutions, Switzerland http://homepage.swissonline.ch/cindymeister (last update Jun 8 2004) http://www.word.mvps.org
This reply is posted in the Newsgroup; please post any follow question or reply in the newsgroup and not by e-mail :-)
googly-al@ashbourne-town.com - 27 Mar 2005 17:59 GMT Cindy M -WordMVP- wrote:
> Hi Alan, > > Hard to offer any advice without knowing HOW you're doing this? Find/Replace, > or looping the Fields collection, or something else? Cindy
Here is a similar bit of code, this just finds each Index Entry Mark, and then highlights the word to the left of the entry - usually the word that is indexed.
If the doc is more then a page and you have your cusor mid-page, the page re-positions itself when the macro ends.
Any help would be greatfully received!
Regards Alan F.
Sub test_highlight_index()
Dim oRange As Range Set oRange = Selection.Range
For Each Field In ActiveDocument.Fields Application.ScreenUpdating = False If Field.Type = wdFieldIndexEntry Then ' If Index entry Field.Select Selection.MoveLeft Unit:=wdCharacter, Count:=1 ' Selection.MoveLeft Unit:=wdWord, Count:=1, Extend:=wdExtend Selection.Range.HighlightColorIndex = wdYellow ' highlight word End If Next Field oRange.Select Application.ScreenUpdating = True End Sub
Jay Freedman - 27 Mar 2005 19:41 GMT >Cindy M -WordMVP- wrote: >> Hi Alan, [quoted text clipped - 35 lines] > >End Sub Hi Alan,
The page display moves because you're working with the Selection, which is mapped 1:1 to the insertion point or selected text on the face of the document. That forces Word to scroll the display, regardless of whether you have ScreenUpdating turned on or off. When your macro re-enables the screen updating, the display jumps to the new position. Word has only a very hazy idea of where things are on the screen -- only whether a particular area is or isn't on-screen -- so it's very hard to control any movement.
The better method is to avoid any reference at all to the Selection, and to use only Range objects instead. Then the insertion point never moves and neither does the display. You don't even need to change ScreenUpdating.
For the subroutine you showed, the Range-based version looks like this:
Public Sub HighlightBeforeXE() Dim oRg As Range, oTempRg As Range Set oRg = ActiveDocument.Range ' Since XE fields are formatted as Hidden, ' arrange to find Hidden text even when it ' isn't displayed. oRg.TextRetrievalMode.IncludeHiddenText = True With oRg.Find .ClearFormatting .Text = " XE " ' find index entry field code .Format = False .Forward = True .Wrap = wdFindStop .MatchCase = False ' Loop as long as we find more fields. Do While .Execute ' At this point, oRg covers the XE ' in an index field. Make another range ' that duplicates oRg... Set oTempRg = oRg.Duplicate ' and use the duplicate to find and ' format the word before the field. With oTempRg ' The opening field brace counts as ' one "word" before the XE, so move ' left by two words. .Move unit:=wdWord, Count:=-2 ' Expand the range to cover the ' whole word. .MoveEnd unit:=wdWord, Count:=1 ' Highlight it. .HighlightColorIndex = wdYellow End With ' The loop now continues from the ' current position of oRg, which ' hasn't been changed by fiddling ' with oTempRg. Loop End With End Sub
In your first post, you mentioned deleting index entry fields. That, too, can be achieved without touching the Selection:
Sub DeleteXEfields() Dim oFld As Field For Each oFld In ActiveDocument.Fields If oFld.Type = wdFieldIndexEntry Then oFld.Delete End If Next oFld End Sub
-- Regards, Jay Freedman Microsoft Word MVP FAQ: http://word.mvps.org
Alan F. - 29 Mar 2005 14:04 GMT > >Cindy M -WordMVP- wrote: > >> Hi Alan, [quoted text clipped - 113 lines] > Next oFld > End Sub Ray many thanks.
Another related question - With the range, in your 1st example, is it possible to use the FieldIndexEntry collection rather then the whole document. So that any real text e.g. XE is not also selected, only true Index Entries?
In the past I used to do all my index selections using "find", then I discovered the wdFieldIndexEntry - which simplified the searches - well at least they required less lines of code - which I assume is better.
Kind regards Alan.
Jay Freedman - 29 Mar 2005 19:12 GMT [...]
>> Hi Alan, >> [quoted text clipped - 88 lines] > >Kind regards Alan. Hi Alan,
Thanks for continuing to ask! You've pushed me to discover something I didn't know before: the .Code property of a Field object returns a Range (I was under the impression that it was a simple String value). This macro achieves the same result as the earlier one (I left out the comments this time):
Sub HighlightBeforeXE() Dim ofld As Field Dim oRg As Range For Each ofld In ActiveDocument.Fields If ofld.Type = wdFieldIndexEntry Then Set oRg = ofld.Code With oRg .Move unit:=wdWord, Count:=-2 .MoveEnd unit:=wdWord, Count:=1 .HighlightColorIndex = wdYellow End With End If Next ofld End Sub
(Technically, there is no such thing as a "FieldIndexEntry collection". There is a Fields collection, in which some Field objects may have a .Type value of wdFieldIndexEntry.)
Going back to my first macro, you can make it find XE only in field codes by changing one line:
.Text = "^d XE " ' find index entry field code
-- Regards, Jay Freedman Microsoft Word MVP FAQ: http://word.mvps.org
Greg - 29 Mar 2005 21:28 GMT Jay,
How about this to highlight each indexed word?
Sub HighlightBeforeXE2() Dim ofld As Field Dim oRg As Range Dim oTempRg As Range Dim i As Integer For Each ofld In ActiveDocument.Fields If ofld.Type = wdFieldIndexEntry Then Set oRg = ofld.Code i = oRg.Words.Count - 4 'The 4 strips out field code With oRg .Move unit:=wdWord, Count:=-1 'move range to left edge of indexed term 'Expand the range to cover the indexed term .MoveStart unit:=wdWord, Count:=-i .HighlightColorIndex = wdYellow End With Set oRg = Nothing End If Next ofld End Sub
Alan F. - 01 Apr 2005 10:45 GMT > Jay, > [quoted text clipped - 12 lines] > .Move unit:=wdWord, Count:=-1 'move range to left edge of indexed > term
> 'Expand the range to cover the indexed term > .MoveStart unit:=wdWord, Count:=-i [quoted text clipped - 4 lines] > Next ofld > End Sub Greg
Good code, it actually attempts to highlight all the words that are marked. (my one only highlighted single words). However, the Entry Marks can also have font and reference text in them, which your macro also counts. e.g. { XE "marked word" \b \i } or even { XE "marked word" \t "See Description" \b \i }
I have attempted to rectify this by modifing your code to count the words between the quotation marks. It works Ok EXCEPT it puts the last string whereever the cursor happens to be in the document. I believe that this is because I Select the "marked words" - sWords, to be able to count them. I have tried ranges etc. to not select the sWords but have failed.
So my question -how can I count the words in sWords without selecting them?
Sub HighightBeforeXE_3() Dim ofld As Field Dim oRg As Range Dim oTempRg As Range Dim oCount As Integer Dim ePos As Integer Dim sWords As String
For Each ofld In ActiveDocument.Fields If ofld.Type = wdFieldIndexEntry Then Set oRg = ofld.Code ePos = InStr(7, oRg, """", 1) ' get the position of the end of the marked entry sWords = Mid(oRg, 6, ePos - 6) ' gets only the words between the " " marks. Selection = sWords oCount = oTempRg.Words.Count ' counts the words in the entry With oRg .Move unit:=wdWord, Count:=-1 .MoveStart unit:=wdWord, Count:=-oCount .HighlightColorIndex = wdYellow End With Set oRg = Nothing End If Next ofld End Sub
Kind Regards Alan F.
Alan F. - 01 Apr 2005 11:46 GMT > Jay, > [quoted text clipped - 12 lines] > .Move unit:=wdWord, Count:=-1 'move range to left edge of indexed > term
> 'Expand the range to cover the indexed term > .MoveStart unit:=wdWord, Count:=-i [quoted text clipped - 4 lines] > Next ofld > End Sub Greg
My last post had some buggy code - please ignore.
I should have said :-
Nearly there! This is better then my code as I was only highlighting a single word. Yours highlights all the words - however the XE field can also contain font formating and "reference" informations and subentries such as :-
{ XE "word and word" \b \i } { XE "word and word" \t "See Description" \b \i } { XE "Descriptions and text:word and word" \t "See Description" \b \i }
I have modified the code to only recognise the actual entry text, checking for words within the 1st set of quotation marks, and after the ":" if one exists.
HOWEVER - I still have a problem as the:-
Selection = sWords oCount = Selection.Words.Count
returns the correct word count, but because I used a "Selection" it puts the sWords string in the actual document text :(
I have tried other ways to count the words, but have not been successful - range.words.count etc. etc.
Any suggestions??
Sub test_HighightBeforeXE_3() Dim ofld As Field Dim oRg As Range Dim oTempRg As Range Dim oCount As Integer Dim ePos As Integer Dim sPos As Integer Dim sWords As String
For Each ofld In ActiveDocument.Fields If ofld.Type = wdFieldIndexEntry Then Set oRg = ofld.Code sPos = InStr(5, oRg, ":", 1) + 1 ' get start position of subentry text if exists If sPos < 6 Then ' if less then 6 the no subentry sPos = InStr(5, oRg, """", 1) + 1 ' gets start position of main entry text End If ePos = InStr(sPos + 1, oRg, """", 1) ' get the position of the end of the marked entry sWords = Mid(oRg, sPos, ePos - sPos) ' gets only the words between the " " marks. Selection = sWords oCount = Selection.Words.Count ' counts the words in the entry With oRg .Move unit:=wdWord, Count:=-1 .MoveStart unit:=wdWord, Count:=-oCount .HighlightColorIndex = wdYellow End With Set oRg = Nothing End If Next ofld End Sub
Regards Alan F.
Greg Maxey - 01 Apr 2005 12:13 GMT Alan,
I am not familiar with anything to count words in a string. I suppose you could evaluate each character and count up the spaces plus 1 or you could use this:
sWords = Mid(oRg, sPos, ePos - sPos) sWordsArray = Split(sWords, " ") oCount = UBound(sWordsArray) + 1
 Signature Greg Maxey/Word MVP See: http://gregmaxey.mvps.org/word_tips.htm For some helpful tips using Word.
>> Jay, >> [quoted text clipped - 92 lines] > > Regards Alan F. Greg - 01 Apr 2005 16:08 GMT Alan,
I monkeyed around with this code a little futher :-)
What if you have: highlight "indexed" terms.{ XE "higlight "indexed" terms" \b \i }
The code would only highlight the: " terms
I added some code to handled "one" pair of quotes in the indexed term:
Sub HighightBeforeXE() Dim ofld As Field Dim oRg As Range Dim oTempRg As Range Dim oCount As Integer Dim ePos As Integer Dim sPos As Integer Dim midPos1 As Integer Dim bQuotedIndex As Boolean Dim midPos2 As Integer Dim sWords As String Dim sWordsArray As Variant
For Each ofld In ActiveDocument.Fields bQuotedIndex = False If ofld.Type = wdFieldIndexEntry Then Set oRg = ofld.Code sPos = InStr(5, oRg, ":", 1) + 1 'start position with subentry If sPos < 6 Then 'no subentry sPos = InStr(5, oRg, """") + 1 'start position End If midPos1 = InStr(sPos, oRg, "\""") If midPos1 > 0 Then bQuotedIndex = True midPos2 = InStr(midPos1 + 2, oRg, "\""") End If If midPos2 > 0 Then ePos = InStr(midPos2 + 2, oRg, """", 1) Else ePos = InStr(sPos + 1, oRg, """", 1) 'end pos End If sWords = Mid(oRg, sPos, ePos - sPos) 'words between the start" end" marks. sWordsArray = Split(sWords, " ") If Not bQuotedIndex Then oCount = UBound(sWordsArray) + 1 Else oCount = UBound(sWordsArray) + 3 End If With oRg .Move unit:=wdWord, Count:=-1 .MoveStart unit:=wdWord, Count:=-oCount .HighlightColorIndex = wdYellow End With Set oRg = Nothing End If Next ofld End Sub
I had worked out something similiar using the Find.Execute method before Jay introduced us to the the oFld.Code.Text range:
Public Sub HighlightIndexedTerms() Dim oRg As Range Dim oTempRg As Range Dim i As Integer
Set oRg = ActiveDocument.Range oRg.TextRetrievalMode.IncludeHiddenText = True With oRg.Find .ClearFormatting .Text = " XE " ' find index entry field code .Format = False .Forward = True .Wrap = wdFindStop .MatchCase = False Do While .Execute 'At this point, oRg covers the XE in an index field. 'Make another range that duplicates oRg... Set oTempRg = oRg.Duplicate 'Use the duplicate to determine the indexed term. With oTempRg .Move unit:=wdWord, Count:=2 'Move range passed first " Do .MoveEndUntil Cset:=Chr(34), Count:=wdForward 'range the XE field term If oTempRg.Characters.Last = "\" Then .MoveEnd unit:=wdCharacter, Count:=2 .MoveEndUntil Cset:=Chr(34), Count:=wdForward 'range the XE field ter End If Loop Until oTempRg.Characters.Last <> "\" i = oTempRg.Words.Count 'count words in indexed term End With Set oTempRg = oRg.Duplicate 'Again match oTempRg to oRg With oTempRg .Move unit:=wdWord, Count:=-1 'move range to left edge of indexed term 'Expand the range to cover the indexed term .MoveStart unit:=wdWord, Count:=-i 'Highlight it. .HighlightColorIndex = wdYellow End With 'The loop now continues from the current position of oRg, which 'hasn't been changed by fiddling with oTempRg. Set oTempRg = Nothing Loop End With End Sub
This would handle multiple quote pairs in the indexed term, but I haven't attempted to address the subentries and references in the field code.
HTH
Alan F. - 05 Apr 2005 12:04 GMT > Alan, > [quoted text clipped - 6 lines] > > I added some code to handled "one" pair of quotes in the indexed term: Greg
You seemed to have cracked it! I'm not sure just how yet, I'm still working my way through the code :-).
You have ditched my Selection and Words.Count, and have introduced me to the UBound function and arrays - which I do not understand what it actually does yet, but that should keep me busy for a bit reading up on it and finding out.
As to nested " ", I don't need to cater for them, as with Word, if you nest them, when you create your Index, it only displays the word between the 1st 2 "" marks. So I'll have a play with your code and remove that bit.
With Word "The "Big Cat" Book" would appear as "The" in the final index. I don't think there is anything that can be done - but hmmmm, that has got me thinking, if I change the " to a ' when I index it then it will appear - e.g. "The "Big Cat" Book" to "The 'Big Cat' Book" I then get "The 'Big Cat' Book" appearing in the Index, better then nothing. - I'll have ago at that one!
Many thanks again for the time you have spent on my problem - it has been most appreciated, and has moved my VBA skills along a notch or 2! I still don't know what I am doing 1/2 the time, but I'm getting there!
Kind regards Alan F.
Alan F. - 05 Apr 2005 14:02 GMT > Alan, > [quoted text clipped - 6 lines] > > I added some code to handled "one" pair of quotes in the indexed term: Greg
Another question if I may,
The search string - "\""" What exactly is this searching for? The \ has stumped me completely?
Regards Alan.
Greg - 05 Apr 2005 15:20 GMT Alan,
My bag. If you index - highlighted "indexed" items
It appears as highlight "indexed" terms{ XE "higlight \"indexed\" terms" \b \i }
The serach string that had you stumped allows us to move past two internal " symbols to find the end of the phrase.
Alan F. - 01 Apr 2005 08:38 GMT > On 29 Mar 2005 05:04:01 -0800, googly-al@ashbourne-town.com (Alan F.)
> wrote: > [quoted text clipped - 124 lines] > > .Text = "^d XE " ' find index entry field code Jay
> Thanks for continuing to ask! You've pushed me to discover something I didn't know before: I'm disillusioned now, I thought you guys knew everything ;-)
I had a play around with it and came up with nearly the same code! The "watch" function in the VBA editor is a boon. Many thanks for introducing me to ranges, if this keeps on, I'll end up as a real programmer!! My Index function macros have been cut by 80% in lines of code now I have binned all the Find strings.
many thanks again regards Alan F.
Jay Freedman - 02 Apr 2005 15:22 GMT >> Thanks for continuing to ask! You've pushed me to discover something I didn't know before: > >I'm disillusioned now, I thought you guys knew everything ;-) Pay no attention to the man behind the curtain. :-)
As a group we know a lot more than any one of us knows (or can remember), and I guess it does start to look like omniscience. No matter how long I keep at this, though, there's always more to figure out.
>I had a play around with it and came up with nearly the same code! The >"watch" function in the VBA editor is a boon. [quoted text clipped - 5 lines] >many thanks again >regards Alan F. Great! Thanks for the thanks, and come back often.
-- Regards, Jay Freedman Microsoft Word MVP FAQ: http://word.mvps.org
Alan F. - 04 Apr 2005 11:44 GMT > Pay no attention to the man behind the curtain. :-) So an old dog can learn new tricks ;-)
many thanks again - til next time!
Kind regards - Alan F.
|
|
|