Riddle me this

G

Greg Maxey

Hi,

I have a snippet of code that applies superscript font:

oWord.SetRange Start:=oWord.Start, End:=oWord.End + 1
oWord.Select
'oWord.Font.Superscript = True
Selection.Font.Superscript = True

I don't understand why I have to select the range and then apply the
formatting to the selection. In another macro I have this code

ActiveDocument.Range.Font.Superscript = True

which I am using to try to solve this riddle. Isn't oWord a Range like
ActiveDocument.Range? Why doesn't oWord.Font.Superscript = True work like
ActiveDocument.Range.Font.Superscript = True

Here is my complete code:

Sub ScratchMacro1()
Dim oPara As Paragraph
Dim oWord As Range
Dim i As Long
Dim myWord As String
Dim mySeq As String

myWord = InputBox("Enter the word to find.")
mySeq = myWord
For Each oPara In ActiveDocument.Paragraphs
i = 0
For Each oWord In oPara.Range.Words
If Right(oWord, 1) = " " Then oWord.MoveEnd Unit:=wdCharacter,
Count:=-1
If LCase(oWord) = LCase(myWord) Then
i = i + 1
oWord.Collapse Direction:=wdCollapseStart
'insert field, reset sequence to 1 for first occurence in paragraph
If i = 1 Then
oWord.Fields.Add Range:=oWord, Type:=wdFieldEmpty, Text:= _
"SEQ " & mySeq & " \r1", PreserveFormatting:=True
Else
'insert field
oWord.Fields.Add Range:=oWord, Type:=wdFieldEmpty, Text:= _
"SEQ " & mySeq & "", PreserveFormatting:=True
End If
'superscript the sequence number
oWord.SetRange Start:=oWord.Start, End:=oWord.End + 1
oWord.Select
'oWord.Font.Superscript = True
Selection.Font.Superscript = True
End If
Next
Next
End Sub


Thanks
 
H

Helmut Weber

Hi Greg,

you are extending the range
into the invisible field code.

Try:
oWord.SetRange Start:=oWord.Start, End:=oWord.End + 20
oWord.Font.Superscript = True
'stop here

and switch "field codes on" or whatever
it is called in English.

Greetings from Bavaria, Germany
Helmut Weber, MVP
"red.sys" & chr(64) & "t-online.de"
Word 2002, Windows 2000
 
G

Greg Maxey

Hmm, I now know why I am riddled. oWord.Font.Superscript is in fact
superscripting the { in my field { SEQ ... } just not the whole field.
Apparently oWord.Select is selecting the whole field string. Can anyone
offer an explanation?

Thanks.
 
J

Jonathan West

Greg Maxey said:
Hmm, I now know why I am riddled. oWord.Font.Superscript is in fact
superscripting the { in my field { SEQ ... } just not the whole field.
Apparently oWord.Select is selecting the whole field string. Can anyone
offer an explanation?

Yes, a Selection cannot select just the opening field brace, so when you
attempt to select a range that is defined as an opening field brace, it
selects the entire field.
 
G

Greg

Jonathan,

Thanks. So I could do this by adding *\ Charformat to my field code
construction, Changing PreserveFormatting to False and extending the
range three characters

oWord.SetRange Start:=oWord.Start, End:=oWord.End + 3

to include the S in SEQ then using

oWord.Font.Superscript = True followed by a
ActiveDocument.Fields.Update at the end of the code

In my application (I don't really have one I was just playing around) I
could use either method. The only reason that I am asking is for futher
knowledge regarding efficiency.

Which method if either is more efficient? I mean is it inefficient to
physically select a range vice redefining the range? Thanks
 
J

Jonathan West

Greg said:
Jonathan,

Thanks. So I could do this by adding *\ Charformat to my field code
construction, Changing PreserveFormatting to False and extending the
range three characters

oWord.SetRange Start:=oWord.Start, End:=oWord.End + 3

to include the S in SEQ then using

oWord.Font.Superscript = True followed by a
ActiveDocument.Fields.Update at the end of the code

In my application (I don't really have one I was just playing around) I
could use either method. The only reason that I am asking is for futher
knowledge regarding efficiency.

Which method if either is more efficient? I mean is it inefficient to
physically select a range vice redefining the range? Thanks

Hi Greg,

It depends on what you mean by "efficient"...

The primary aim is to have the program do the required task reliably. The
secondary aim is to do this as fast as possible. The reason that speed is
only the secondary aim is because it is usless for a program to do the wrong
thing very quickly!

Based on your description, it appears that you have two methionds of
achieving the same effect. In Word, this is a very common situation, and it
often happens that there are even more than two ways of doing many things.
In such a situation, the following considerations are worth considering

1. Which method runs faster?
2. Do any methods result in additional side-effects?
3. Will one method work correctly in a wider range of conditions?
4. Is any method easier to code than the others?

These points are not listed in order of importance, because the order of
importance will change from case to case.

Regarding speed, it might or might not be important depending on what you
are doing and how often it is repeated. A routine that takes 0.1s to run is
not going to benefit greatly from optimisation unless it is run repeately
inside a loop.

Side-effects are hard to discuss generally, byt the most obvious one in the
example you have given is that one method moves the selection point while
the other does not. Only you can decide whether that is an important
side-effect. If it is, and you still decide for other reasons that using the
Selection is a good idea, you can always restore the selection to its
original position by using code like this

Dim oStart as Range
Set oStart = Selection.Range

' your code here

oStart.Select


Wider ranges of conditions are also hard to talk about, and in many cases
there is no different between methods.

Ease of coding is entirely subjective, and depends on your familiarity with
different objects and methods and coding styles. If you have code that
works, whether written by you or someone else, it is usually easier to use
it than to go in for wheel-reinvention.
 
H

Helmut Weber

Hi Greg,

if it comes to speed, how about this one?

Of course, I have omitted some stuff,
and the variable names are really very short, ;-)
as I am just playing around, too.

Sub SpeedSpeed()
Dim p As Paragraph ' object paragraph
Dim r As Range ' range of word
Dim i As Integer ' counter of words
Dim s As String ' string of word
s = "let "
For Each p In ActiveDocument.Paragraphs
i = 0
For Each r In p.Range.Words
If s = r Then
i = i + 1
r.Collapse Direction:=wdCollapseStart
r.Text = CStr(i)
r.Font.Superscript = True
End If
Next
Next
End Sub

Greetings from Bavaria, Germany
Helmut Weber, MVP
"red.sys" & chr(64) & "t-online.de"
Word 2002, Windows 2000
 
G

Greg

Helmut,

It misses something like "To let." Changed to this is works great:

Sub SpeedSpeed()
Dim p As Paragraph ' object paragraph
Dim r As Range ' range of word
Dim i As Integer ' counter of words
Dim s As String ' string of word
s = "let"
For Each p In ActiveDocument.Paragraphs
i = 0
For Each r In p.Range.Words
If Right(r, 1) = " " Then r.MoveEnd Unit:=wdCharacter, Count:=-1
If s = r Then
i = i + 1
r.Collapse Direction:=wdCollapseStart
r.Text = CStr(i)
r.Font.Superscript = True
End If
Next
Next
End Sub

Thanks.
 
G

Greg

Jonathan,

Thanks for the time you spent with this explanation. You were right.
Helmut provided a third solution much simpler and probably faster.
 
J

Jonathan West

Greg said:
Helmut,

It misses something like "To let." Changed to this is works great:

Sub SpeedSpeed()
Dim p As Paragraph ' object paragraph
Dim r As Range ' range of word
Dim i As Integer ' counter of words
Dim s As String ' string of word
s = "let"
For Each p In ActiveDocument.Paragraphs
i = 0
For Each r In p.Range.Words
If Right(r, 1) = " " Then r.MoveEnd Unit:=wdCharacter, Count:=-1
If s = r Then
i = i + 1
r.Collapse Direction:=wdCollapseStart
r.Text = CStr(i)
r.Font.Superscript = True
End If
Next
Next
End Sub

Thanks.

Hi Greg,

I would strongly recommend that you indent the code inside loops so that you
can easily see where loops & branches begin & end. It makes code much easier
to understand and follow when you are trying to debug it.

You can read more about this in the following article

The art of defensive programming
http://word.mvps.org/FAQs/MacrosVBA/MaintainableCode.htm

Also, Stephen Bullen has written a wonderful free add-in called Smart
Indenter which automatically applies a consistent indenting style to all the
lines in a routine, module or project. You can find it here

http://www.oaltd.co.uk/Indenter/Default.htm
 
G

Greg

Jonathan,

I usually do. I did here but it doesn't seem to appear that way when I
cut and pasted in the message window. I have read your article
repeatedly :) I will have a look at the addin. Thanks for all of
your help and patience when I sometimes ask the same question 2 or 3
times.
 
G

Greg Maxey

Helmut,

As the two of us are just playing around, I thought I would try to expand
your suggestion a bit. It is a fast and simple way to process the
paragraph, but if the user then edits the paragraph (adds or removes counted
words) then there is a mess. I cobbled together the following code which
appears to do a decent job reproccessing the document if the macro is run a
second time using the same search word. You are welcome to try to break it
or offer suggestions for improvement. I don't really know what it is good
for, but it was good mental exercise:

Sub FindAndNumberWords()
'Sequentially numbers each occurance of a specified word
'Resets numbering at the start of each paragraph

Dim oPara As Paragraph
Dim oWord As Range
Dim i As Integer
Dim FindStr As String
Dim RedoChk
FindStr = InputBox("Type word to find")
For Each oPara In ActiveDocument.Paragraphs
i = 0
For Each oWord In oPara.Range.Words
If Right(oWord, 1) = " " Then oWord.MoveEnd Unit:=wdCharacter, Count:=-1
If LCase(FindStr) = LCase(oWord) Then
i = i + 1
oWord.Collapse Direction:=wdCollapseStart
oWord.Text = CStr(i)
oWord.Font.Superscript = True
End If
RedoChk = LCase(oWord) Like LCase("#*" & FindStr & "")
If RedoChk Then
i = i + 1
oWord.MoveEnd Unit:=wdCharacter, Count:=-Len(FindStr)
oWord.Text = CStr(i)
oWord.Font.Superscript = True
End If
Next
Next
End Sub
 
H

Helmut Weber

Hi Greg,
not much to add, though I'd love to do so.
The only marginal thing could be, to convert
"findstr" to lowercase only once,
at the very start of the sub.

Then
If LCase(FindStr) = LCase(oWord) Then
would become
If FindStr = LCase(oWord)
and
RedoChk = LCase(oWord) Like LCase("#*" & FindStr & "")
would become
RedoChk = LCase(oWord) Like "#*" & FindStr

But I could not see any change in performance,
about 20 seconds, with more then 12000 numbers
to add in a 100 pages doc, containing just text only,
and no tables! As to operate on ranges in tables
is sometimes much slower (10 to 20 times) than using
selection.

See the posting:
Processing paragraphs with find
by Conny Roloff.

Have a nice day.

Greetings from Bavaria, Germany
Helmut Weber, MVP
"red.sys" & chr(64) & "t-online.de"
Word 2002, Windows 2000
 

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