PDA

View Full Version : Solved: Position on page



WorkerBee
03-27-2005, 12:15 AM
Greetings, all

I'm seeking help in VBA for Word - I'm trying to write a bit of code which will break some kinds of paragraphs across pages differently than Word normally does. In order to do that, I need to determine the position of the insertion point relative to the page, in inches, lines, or something I can measure.

Can anyone start me in the right direction?

-WB

TonyJollans
03-27-2005, 01:30 AM
Hi WorkerBee,

Welcome to VBAX!

Personally I think this kind of activity is contrary to the nature of Word. You give Word a set of rules, and you give it the document content and it word processes the two together to make a complete document; it adjusts automatically for different paper sizes, different printers, etc. If you want to post-process the result you have a difficult time ahead of you. What effect are you looking to achieve? Is there not some way you could use Word's rules to achieve it?

That said, the information you are asking for is available from:

Selection.information(wdHorizontalPositionRelativeToPage)
Selection.information(wdVerticalPositionRelativeToPage)

WorkerBee
03-27-2005, 02:35 PM
Tony, thanks for the information.

As to the question of 'why,' it's just as you say. I'm trying to out-process the word processor.

In fact, I'm creating a VB set for formatting film scripts, which utilize a complex set of rules. I created styles for each of the types of paragraphs used in a script, and some vb code which goes through the script after it's finished and conforms the document to the conventions of scripts.

Relevant to this particular effort, each dialogue-style paragraph is preceeded by a paragraph style made for the character's name.

i.e.




TONY

Personally I think this kind of activity is
contrary to the nature of Word. You give
Word a set of rules, and you give it the
document content and it word processes
the two together to make a complete
document; it adjusts automatically for
different paper sizes, different printers,
etc. If you want to post-process the
result you have a difficult time ahead of
you. What effect are you looking to
achieve? Is there not some way you
could use Word's rules to achieve it?
I have the character and dialogue paragraphs set to always keep together. Sometimes, when there is a very long speech near the end of a page, it leaves an unacceptably large white space at the bottom of the page so that it can keep the entire character and speech together.

The common solution in scripts is to break the speech at the bottom of the page, adding the parenthetical "(MORE)" at the bottom of that page, and starting the next page with the character's name with an added (CONT'D). i.e.




TONY

Personally I think this kind of activity is
contrary to the nature of Word.You give
Word a set of rules, and you give it the
document content and it word processes
the two together to make a complete
document; it adjusts automatically for
different paper sizes, different printers,
etc. If you want to post-process the





(MORE)
-----------------page break



TONY (CONT'd)
result you have a difficult time ahead of
you. What effect are you looking to
achieve? Is there not some way you
could use Word's rules to achieve it?

I want to use the power of the computer to free me from the drudgery of searching through each document manually and making these changes.

And to make matters worse, I will make a corollary operation which will go through the document and REMOVE all of those "(MORE)" and "(CONT'D)" and extra character names in case I want to re-write some of the text and change the page breaks.

If I had the money to do so at this time, I'd just buy one of the off-the-shelf one-trick-pony script-writing word processors. But I've got to sell a script to pay for it.

In my defense, I am heavily using Word's templates, styles, pagination, headers, footers, and summary-tracking features.

Again, I thank you for your help on this - I appreciate your sharing of your time and experience.

-Curt

TonyJollans
03-27-2005, 05:17 PM
Interesting, Curt. I don't think there's any real way to do that in Word (bar coding it yourself) but it seems just like a word-processing type of thing which ought to be possible.

I'm not entirely sure right now how I'd go about it but I would think you could determine where the page break was in a couple of ways without using physical position on the page like that.

fumei
05-06-2005, 08:32 AM
This couild be done with VBA. Just curious, but how is this going?

MOS MASTER
05-07-2005, 11:13 AM
This couild be done with VBA. Just curious, but how is this going?
Hi, :D

Sure but like Tony says it will be hard!

Tony has posted some of the Information lines VBA uses to give coordinates but I would certainly also use:
MsgBox Selection.Information(wdFirstCharacterLineNumber)


It returns the line you're at and will be very usefull if you're building your document dynamicly!

But this sort of thing is so hard to to because Word has a dynamic body and things will be dependending on so much factors..to name some:
* Page set-up
* Font sizes
* Paragraph settings

This list could go on and on but I'm sure cursious just like you if the OP has made this work allready..

Enjoy! :whistle:

fumei
05-09-2005, 07:51 AM
Well yes it would be a bit of work, but not HUGELY. Break it out logically.

You have a Style. The rule is:

IF the paragraph using the Style crosses over to another page THEN
1. insert some space in the paragraph before the word processed page break
2. add the "MORE" text
3. add a forced page break
4. add the "CONT" text.

You can detect the page crossing with something like:

Sub StyleParaAcrossPages()
Dim mPara As Paragraph
Selection.HomeKey unit:=wdStory
For Each mPara In ActiveDocument.Paragraphs
If mPara.Style = "NewStyle1" Then
If mPara.Range.End > _
ActiveDocument.Bookmarks("\page").Range.End Then
' ***********
' replace below with the routine to
' break the paragraph with "MORE" and
' page break

MsgBox "Goes to next page"
' if DOES go to next page
' need to move Selection
' to keep using \page bookmark
Selection.GoTo What:=wdGoToPage, Which:=wdGoToNext, Count:=1, Name:=""
Else
MsgBox "Nope."
End If
End If
Next
End Sub

I have not included the routine to make the actual text insertion and page break. Hey ya gotta work! Plus it would depend on whether you would use a special style for this temporary (possibly....likely) text. Whatever method, the actual logic would use the character count from the "\page" Range.End, back up the requirement length, insert the "MORE" and page break.....blah blah blah.

MOS MASTER
05-09-2005, 07:57 AM
Hi Gerry, :D

This looks promissing but like you've said your not there yet.
I will have to play with your code to see if its doing what I aspect from it.

Do a postback later.
Still wondering though if the OP still has interest in this subject..:whistle:

fumei
05-09-2005, 08:40 AM
That sounded vaguely challenging, but hey, what the heck.
Sub StyleParaAcrossPages()
Dim mPara As Paragraph
Selection.HomeKey Unit:=wdStory
For Each mPara In ActiveDocument.Paragraphs
If mPara.Style = "NewStyle1" Then
If mPara.Range.End > _
ActiveDocument.Bookmarks("\page").Range.End Then
Selection.SetRange _
Start:=ActiveDocument.Bookmarks("\page").Range.End - 128, _
End:=ActiveDocument.Bookmarks("\page").Range.End - 128
Call FixMORE
Else
MsgBox "Nope."
End If
End If
Next
End Sub


Sub FixMORE()
With Selection
.TypeParagraph
.TypeParagraph
.MoveLeft Unit:=wdCharacter, Count:=1
NormalTemplate.AutoTextEntries("MORE").Insert _
Where:=Selection.Range, _
RichText:=True
.Style = ActiveDocument.Styles("myMORE")
.TypeParagraph
' next page stuff
.TypeParagraph
.TypeParagraph
.MoveLeft Unit:=wdCharacter, Count:=1
NormalTemplate.AutoTextEntries("CONT").Insert _
Where:=Selection.Range, _
RichText:=True
.Style = ActiveDocument.Styles("myMORE")
.TypeParagraph
End With
End Sub

I used a Style - myMore - for the (More) text. The VERY IMPORTANT thing to consider is that you will have to figure out, ahead of time, the character counts to deal with.

The original text has the same font size as the next paragraph with "(MORE)", but obviously the character count will now be different. Less words, whole paragraphs.

You need to make a paragraph that DOES go over, get the position number of the end of the page, then get the position number of the end of the line that you are going to break.

If you are using Styles, then this will be the same every time. In my test case, this means 128 characters. This is hard coded in. IF you are using styles. So there will, in my case, always 128 characters between the end of the page and where I want to start the MORE (also a Style) stuff.

Or....will it? NOPE. What if there are only two lines of this style, and 128 characters (my test doc had BIG paragraphs) actually brings you out of that paragraph? Ah, so sorry, but you then have to test this. It is fairly easy using a Range object.

The question thoug is - what do you DO about it. This is a design element, so i can not answer. Is it acceptable to use this (MORE) format if there is only ONE line on page A, all the rest of the paragraph on page B? Or would you move a one-liner over to the next page?

better specs - better code

The rest of the code is self explanatory.

MOS MASTER
05-09-2005, 08:47 AM
That sounded vaguely challenging, but hey, what the heck.

Hahaha not really but I knew you'd pick up on it! :p

I've copied everyting to a workbook and must have a go at it...but at the moment my mailbox is overflowing and this isn't a question to answer without testing first. (for me at least)

Later...

WorkerBee
05-09-2005, 11:09 PM
Greetings, all.

I've been away from the forum, working on my real job, and I've put some time in this already.

So far, here's how my code goes. I'm sure some will find some stylistic faults, but then I'm an amateur. I know there are too many literals, and I promise to clean that up when I get it all working.

This subroutine is called when the first paragraph at the top of a page is formatted with the style "Character," and begins with the insertion point at the beginning of that line.

Sometimes the name of the character already has the word "(CONT'D) following it because a person was talking, the dialogue was interrupted by narrative, then the dialogue continues. Additionally, the style requires that a sentence not be broken across a page. Even though this is creating a new paragraph in their speech, it's an accepted (and required) part of the format.

The word "(More)" at the bottom of the page is formatted with the style "More Dialogue" and the inserted character name at the top of the page is formatted with the style "More Character" because I will write a corresponding macro to remove these formatted items so that the script can be re-edited and re-formatted.


Sub FixDialogBreak()
Dim VertPos As Variant, NumLines As Integer, CharName As String

'Move backwards one line
Selection.MoveLeft unit:=wdCharacter, Count:=1

'Check the current vertical position. If it's greater than 650, nothing should
' be done because there's not enough room. Move on

VertPos = Selection.Information(wdVerticalPositionRelativeToPage)
If VertPos > 668 Then
Selection.MoveRight unit:=wdCharacter
GoTo BreakDone
End If

'Calculate how many lines can be moved onto earlier page
'VertPos is in points (72 points = 1 inch). Bottom of page is 719.1. Each line is 12 pts
'Remove the page/section break that's just been put there
NumLines = Int(((706 - VertPos) / 12) - 1)
Selection.Delete unit:=wdCharacter, Count:=1

'Move back down one line, capture the character name
'Selection.MoveDown Unit:=wdLine, Count:=1
Selection.EndKey unit:=wdLine, Extend:=wdExtend
CharName = Selection.Text

'Move forward x lines
Selection.MoveDown unit:=wdLine, Count:=NumLines - 1
Selection.EndKey unit:=wdLine

'Move backwards, find the next preceding period, as we can't break in the middle of a
' sentence. If there are none prior to hitting the character name, we can't break the
' dialogue any earlier than it is, so give up.

Do

Selection.MoveLeft unit:=wdCharacter, Count:=2
Selection.MoveRight unit:=wdCharacter, Extend:=wdExtend
If Selection.Style <> "Dialogue" Then GoTo BreakDone 'Ran out of dialogue

Loop Until Selection = "." Or Selection = "!" Or Selection = "?"

Selection.MoveRight unit:=wdCharacter
Do
Selection.MoveRight unit:=wdCharacter
Selection.MoveRight unit:=wdCharacter, Extend:=wdExtend
Loop Until Selection <> " "

If Selection = Chr(13) Then GoTo BreakDone

Selection.MoveLeft unit:=wdCharacter
'Add the (MORE) and insert page break here
Selection.TypeText Text:=Chr(13) & "(MORE)" & Chr(13)
Selection.MoveLeft unit:=wdCharacter
Selection.Style = "More Dialogue"
Selection.InsertBreak Type:=wdSectionBreakNextPage
Selection.Delete unit:=wdCharacter, Count:=1

'Paste in character name along with (CONT'D)
Selection.TypeText Text:=CharName
Selection.MoveLeft unit:=wdCharacter
If Right$(CharName, 10) = "(CONT'D) " + Chr$(13) Then GoTo SKIPCONTD 'There's already a continued there
Selection.TypeText Text:=" (CONT'D)"
SKIPCONTD:
Selection.Style = "More Character"
Selection.HomeKey unit:=wdLine

BreakDone:

End Sub


This is all working pretty well so far.

I don't want there to be a strange short line of dialogue with only a couple of words left at the bottom of a page (in case of a short sentence), so I need to add some code to take that into account. However, in the depths of my ignorance, I don't know what the code is which will return to me the column position of the insertion point, that is, how many characters is the insertion point from the start of the line? Can someone help?

-WB

fumei
05-10-2005, 07:05 AM
Hi,

First off, your code will run a bit better if you use With statements. As in:

With Selection
.MoveLeft unit:=wdCharacter
'Add the (MORE) and insert page break here
.TypeText Text:=Chr(13) & "(MORE)" & Chr(13)
.MoveLeft unit:=wdCharacter
.Style = "More Dialogue"
.InsertBreak Type:=wdSectionBreakNextPage
.Delete unit:=wdCharacter, Count:=1

'Paste in character name along with (CONT'D)
.TypeText Text:=CharName
.MoveLeft unit:=wdCharacter
If Right$(CharName, 10) = "(CONT'D) " + Chr$(13) Then Goto SKIPCONTD 'There's already a continued there
.TypeText Text:=" (CONT'D)"
End With

You asked how to find out the number of characters from the insertion point to the start of the line. Here is one way - there are others.
Function ToStart() As Long
Dim r As Range
Set r = ActiveDocument.Range _
(Start:=ActiveDocument.Bookmarks("\line").Range.Start, _
End:=Selection.Range.Start)

ToStart = r.ComputeStatistics(wdStatisticCharacters)
Set r = Nothing
End Function

Sub GetCharacters()
MsgBox ToStart
End Sub

However, you had better make sure the insertion point (the Selection) is, in fact, where you want it to be. As this code needs to run (I assume) from the start of the document checking for these paragraph breaks, you must make sure you are moving the Selection along with it.

I also notice you have added the requirement that you do NOT break the paragraph in the middle of a sentence, only at a period. In your original post on this:

"etc. If you want to post-process the
(MORE)

-----------------page break
TONY (CONT'd)

result you have a difficult time ahead of "

you did not have this requirement. Once again - better specs, better code. It also makes it more difficult, and complicated. You have done a gerat job so far!

WorkerBee
05-10-2005, 05:00 PM
Thanks for the advice, Gerry. I'll make some of those modifications soon.

I was hoping for an easier way to find the character column position (after all, it's displayed at the bottom of the Word window), but my wishin' hasn't always made things come true.

You're correct that the design specs changed. It's my own fault for not paying close enough attention. It looked funny after completed, then I read deeper into the style book and found myself wrong.

As for difficult or complicated: if it were easy, it wouldn't need doing. We have a saying in my business: "If a job's worth doing, it's worth doing over and over."

-Curt

fumei
05-11-2005, 06:44 AM
Yes it is displayed in Word, and guess what? Word make a range object and calculates the value every time the selection point is moved. It calculates it just like the code above. That IS the easy way.

But again, be careful that the Selection point is, in fact, moved to where you want it to be. Consider doing your calculation using a range.

As for, say, two lines being too small, and in which case you want to move the whiole thing to the next page, I suspect the faster way to get this done is determine the character count and hard code it.

Do the break as "normal", then do a secondary calculation using a range object for the range of the last paragraph start, and the predefined bookmark "\page" End. If it is < 170 characters (approx. 2 lines) then dump the page break and move it to the beginning of the paragraph.

MOS MASTER
05-11-2005, 09:40 AM
I was hoping for an easier way to find the character column position (after all, it's displayed at the bottom of the Word window), but my wishin' hasn't always made things come true.-Curt
Hi Curt, :D

Many wise Words off Gery all of them true of course...

But there is infact an easy way to retrieve that value of Col that you see in the statusbar (bottom window):
MsgBox Selection.Information(wdFirstCharacterColumnNumber)


Enjoy! :whistle:

fumei
05-11-2005, 12:47 PM
Still need to make sure Selection is on the correct line.

Would still need the paragraph range start to determine the number of characters to paragraph start - which may not be on the same line....

But yes, you have a very valid point. I had also forgotten....sigh.... that Range.ComputeStatistics calculates very differently that Selection.Information.

For example. the Selection is at the left most of a line.

Selection.Information returns 1 - in fact can not return a 0
Range.Calculate returns 0 - there are no characters

Selection.Information includes punctuation and spaces.
Range.CalculateStatistics does not.

I :bow: to Joost

MOS MASTER
05-11-2005, 12:51 PM
I :bow: to Joost
Are we the new Laurel and Hardy?

I :bow: to you as well!

fumei
05-12-2005, 06:50 AM
Apparetly we are. Do you have a preference for which one?

MOS MASTER
05-12-2005, 09:26 AM
Nopes..let the audience decide! :whistle:

WorkerBee
05-12-2005, 05:05 PM
Thank you MOS Master (and you others, too). That was indeed what I was seeking. Now I can find true happiness.

-Curt

MOS MASTER
05-13-2005, 10:16 AM
Hai Curt, :D
You happy me happy...you're welcome! :beerchug: