Computing range position

J

Jean-Guy Marcil

Hi there,

I have a macro that calculates the vertical length of the currently selected
range, if this selection in within a single page.

I use something like:

With rgeCurrent
.Paragraphs(1).Range.Characters(1) _
.Information(wdVerticalPositionRelativeToPage)
End With

Where rgeCurrent is a range.

But, when the range is within a table, I found that the only way to get
reliable measurements was to use "wdVerticalPositionRelativeToTextBoundary"
instead of "wdVerticalPositionRelativeToPage". But, in such case I get
results relative to the cell holding the range.

Problem:
How to calculate the length of a selection that encompasses many cells?
"wdVerticalPositionRelativeToTextBoundary" at the end of the range returns
the position of the end of the range relative to the cell holding the end of
the range. So I cannot get the full length of the range by adding the
starting and ending position like I do outside of tables with
"wdVerticalPositionRelativeToPage".

I can think of a few ways around that, but they are quite involved and may
possibly not work if there are merged cells...

It is very possible that I have overlooked or misused something...
Does anybody know how to get the vertical length of a range in tables.

And what if the range starts outside a table and finishes in a table (or
vice cersa)?
 
M

Mike

Hi there,

I have a macro that calculates the vertical length of the currently selected
range, if this selection in within a single page.

I use something like:

With rgeCurrent
   .Paragraphs(1).Range.Characters(1) _
       .Information(wdVerticalPositionRelativeToPage)
End With

Where rgeCurrent is a range.

But, when the range is within a table, I found that the only way to get
reliable measurements was to use "wdVerticalPositionRelativeToTextBoundary"
instead of "wdVerticalPositionRelativeToPage". But, in such case I get
results relative to the cell holding the range.

Problem:
How to calculate the length of a selection that encompasses many cells?
"wdVerticalPositionRelativeToTextBoundary" at the end of the range returns
the position of the end of the range relative to the cell holding the end of
the range. So I cannot get the full length of the range by adding the
starting and ending position like I do outside of tables with
"wdVerticalPositionRelativeToPage".

I can think of a few ways around that, but they are quite involved and may
possibly not work if there are merged cells...

It is very possible that I have overlooked or misused something...
Does anybody know how to get the vertical length of a range in tables.

If you have a selection object sObj, how about
sObj.Cells.Height
?

You would need to set HeightRule to wdRowHeightAtLeast somewhere prior
to the above, otherwise sObj.Cells.Height returns wdUndefined.
And what if the range starts outside a table and finishes in a table (or
vice cersa)?


You could add a Frame around your selection and try applying the
Height property to the frame.

Just a thought. I haven't tried it myself. Maybe others can comment.

--Mike Jr.
 
H

Helmut Weber

Hi Jean-Guy,

I'm sorry, I can reproduce only parts of that.
This one, gives kind of reliable results here and now:

Sub Test0()
Dim rng As Range
Dim x1 As Single
Dim x2 As Single
Set rng = Selection.Range
With rng.Characters
x1 = .First.Information(wdVerticalPositionRelativeToPage)
x2 = .Last.Information(wdVerticalPositionRelativeToPage)
End With
MsgBox x2 - x1
End Sub

But, if the last character
in the range is the end-of-cell mark
in a cell that contains paragraphs or lines,
that cell's height is set to the lines height
or to zero.

Example, in a cell, all of the cell selected:


z<end-of-cell>

x2-x1 = 0

Example, in a cell, all of the cell
but the end-of-cell mark selected:


z<end-of-cell>

x2-x1 = 28.20001

In addition, you have to add the height
of the first line of the range, which I have set to 14.

The problem seems to be to avoid an
end-of-cell mark as last character of the selection.

Well, I don't know better here and now,
the complications are endless.




--

Greetings from Bavaria, Germany

Helmut Weber, MVP WordVBA

Vista Small Business, Office XP
 
J

Jean-Guy Marcil

Mike said:
If you have a selection object sObj, how about
sObj.Cells.Height
?

You would need to set HeightRule to wdRowHeightAtLeast somewhere prior
to the above, otherwise sObj.Cells.Height returns wdUndefined.


You could add a Frame around your selection and try applying the
Height property to the frame.

Just a thought. I haven't tried it myself. Maybe others can comment.

I like the idea of the frame, especially since it can cover a partial table
area, which is what I need.

It works well, but there is a problem. The height is also undefined (Auto).
If I manually change it using the UI to Exactly or At Least, the height
value automatically picks up the current selection height. Great!

I tried 3 different ways to set it with VBA:

A) Frame properties
myFrame.HeightRule = ...

B) Using wdDialogFormatFrame
Set dlgFrame = ...
With dlgFrame
.HeightRule = 2
.Execute
End With

C) SendKeys
Sendkeys "g{Down}{Down}{Enter}{Enter}
Dialogs(wdDialogFormatFrame).Show

A) and C) have the same effect. The frame height rule is modified, but
instead of taking the current value, it defaults to 1 inch.
B) Seemingly has no effect, but the Undo list does have an entry for Frame
Formatting. So it is picked up by the Undo stack, but it does not have any
effect, or I am doing it wrong.

Too bad though, it did look promising!

I'll keep digging a bit and see if I can get it to work...
 
J

Jean-Guy Marcil

Hi Helmut, comments inline...

Helmut Weber said:
Hi Jean-Guy,

I'm sorry, I can reproduce only parts of that.
This one, gives kind of reliable results here and now:

Sub Test0()
Dim rng As Range
Dim x1 As Single
Dim x2 As Single
Set rng = Selection.Range
With rng.Characters
x1 = .First.Information(wdVerticalPositionRelativeToPage)
x2 = .Last.Information(wdVerticalPositionRelativeToPage)
End With
MsgBox x2 - x1
End Sub

You are absolutely right!
But, if the last character
in the range is the end-of-cell mark
in a cell that contains paragraphs or lines,
that cell's height is set to the lines height
or to zero.

Example, in a cell, all of the cell selected:
z¶
z¶
z<end-of-cell>

x2-x1 = 0

That is the reason why I had the problem in the first place... In my inital
tests, when you select more than a cell, Word forces you to select the whole
cell. As far as I know, you cannot select from the middle of a cell to the
middle of another cell.

So, in my tests, the last character selected was alwasy a ¤... It is only
now that I realize that this is why my results were off... Funny, because I
had already noticed the impact of ¤ for some other aspect of this project,
but when I got to this part, somehow, I did not connect the dots! Talk about
not seeing the forest because of the tree!
Example, in a cell, all of the cell
but the end-of-cell mark selected:
z¶
z¶
z<end-of-cell>

x2-x1 = 28.20001

In addition, you have to add the height
of the first line of the range, which I have set to 14.

Well, the way I have desinged it, I have to take into account the height of
the last character itself. Of course, if several characters in the last line
of the range have different size font, the resuilts will be slightly off. But
I do not need that level of accuracry for now... So no need to scan all
characters in the last line... I just iterate all the cells (in case of
merged cells, I cannot acces row objects) and find the one that returns the
highest wdVerticalPositionRelativeToPage value and that is enough!
The problem seems to be to avoid an
end-of-cell mark as last character of the selection.

That is easily done, in a range involving many cells, the last character is
always a ¤. So you only have to determine if the ¤ is the only character in
the cell:

If .Characters.Count = 1 Then
sngPos = .Characters.Last.Information(wdVerticalPositionRelativeToPage)
Else
sngPos =
..Characters.Last.Previous.Information(wdVerticalPositionRelativeToPage)
End If
 
J

Jean-Guy Marcil

Helmut Weber said:
Hi Jean-Guy,

I'm sorry, I can reproduce only parts of that.
This one, gives kind of reliable results here and now:

<...snip...>

Hi again Helmut,

I just realized something while doing further testing with rows split over
two pages. Let's say that the first cell of such a row contains 10
paragraphs, 3 at the bottom of page 1 and 7 at the top of page 2.

If I select a range representing paragraphs 6 and 7, I have a range that is
entirely contained at the top of page two.

When I run:

Set myShape = ActiveDocument.Shapes.AddLine(1, 1, 1, 10, rngCurrent)

where "rngCurrent" is a range that was set to those two paragraphs, I
expected the code to anchor the shape to the first paragraph of the range
(paragraph 6 in my example). But instead, it insists on anchoring the shape
to the first paragraph in the cell, at the bottom of page 1. So when my code
finishes running, the line drawn is perfect in every way I want, except it is
on page one...

I tried collpasing the range to a an insertion point at the beginning of
paragraph 6, same results...

Any way you (or anybody else!) know around this?

TIA!
 
H

Helmut Weber

Hi Jean-Guy,
Any way you (or anybody else!) know around this?

no, though I've tried hard.

Lets hope for somebody else.



--

Greetings from Bavaria, Germany

Helmut Weber, MVP WordVBA

Vista Small Business, Office XP
 
M

Mike

I like the idea of the frame, especially since it can cover a partial table
area, which is what I need.

It works well, but there is a problem. The height is also undefined (Auto)..
If I manually change it using the UI  to Exactly or At Least, the height
value automatically picks up the current selection height. Great!

I tried 3 different ways to set it with VBA:

A) Frame properties
      myFrame.HeightRule = ...

B) Using wdDialogFormatFrame
      Set dlgFrame = ...
      With dlgFrame
         .HeightRule = 2
         .Execute
      End With

C) SendKeys
      Sendkeys "g{Down}{Down}{Enter}{Enter}
      Dialogs(wdDialogFormatFrame).Show

A) and C) have the same effect. The frame height rule is modified, but
instead of taking the current value, it defaults to 1 inch.
B) Seemingly has no effect, but the Undo list does have an entry for Frame
Formatting. So it is picked up by the Undo stack, but it does not have any
effect, or I am doing it wrong.

Too bad though, it did look promising!

I did a little more digging last night. I think that determining
vertical length is an inherent weakness in MS Word VBA.

You would need to grab control after the formatting for Print Layout
view had completed. I don't know how to do that from VBA. You may be
struggling with a hard problem. However, good luck. It's been
instructive just thinking about it.
 
J

Jean-Guy Marcil

Helmut Weber said:
Hi Jean-Guy,


no, though I've tried hard.

Lets hope for somebody else.

Thanks for your time...
Unless someone has a solution, I guess I'll have to make this a limitation
of what my code can do... I hate doing that!

Cheers!
 

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