Macro to set page margins

H

Heather Mills

Every time I need to print on a card of envelope, I end up screaming
at Word or the dog (poor thing), because Word makes it so difficult to
align text on custom size paper. I've tried several approaches, but
they all have serious drawbacks.

A few days ago, I asked over on microsoft.public.word.newusers if
anyone knew a way to do this. Suzanne said it had been a problem for
her as well.

While fiddling with it yet again (grrrr...), I realized that Word (and
my printers) are really only comfortable with letter paper. So, I
resurrected a method I've used before, which is to adjust the page
margins so that only the printable area of the card or envelope
remains. This actually words well and is reliable.

The only problem with it is that calculating (yuk) the margins is
tedious and error-prone. Then I remembered that that what's computers
are for, right?

So, with new energy, I created a little spreadsheet to debug the
calculations once and for all. I have them mostly working. Now I'd
like to put them in a macro (UDF?) so I can summon them when needed.

Sadly, I'm a klutz with macros. I've written a few, but it's painful.
So, I'll provide the formulas. If someone can take a first stab at a
macro, I'll then polish it up (no doubt with more help here) and then
make it available to everyone. There has to be at least one other
person who has wanted to print on odd forms, but have up. ;-)

These are the parameters (constants) I have defined so far with some
sample settings. I'll probably need a couple more.

Variable Sample Definition
PrtrMarg 0.30 Printer margin (non-printable area).
PageHgt 8.50 Height of the selected paper size.
PageWid 11.00 Width of the selected (logical) paper size.
PaperHgt 4.00 Height of the physical paper (<= PageHgt).
PaperWid 6.00 Width of the physical paper (<= PageWid).
PaperMargTop 0.50 Top margin of physical paper.
PaperMargBot 0.50 Bottom margin of physical paper.
PaperMargLft 0.75 Left margin of physical paper.
PaperMargRgt 0.75 Right margin of physical paper.

Here are the formulas with the values using the settings above. They
are not quite perfect, but they are pretty close. I'll keep fiddling.

Formula Value
MargTop = PageHgt - PaperHgt + PaperMargTop 5.00
MargBot = Max(PrtrMarg, PaperMargBot) 0.50
MargLft = Max(PrtrMarg, PaperMargLft) 0.75
MargRgt = PageWid - PaperWid + PaperMargRgt 5.75

The actual print area can be calculated using these formulas

Formula Value
PrintWid = PaperWid - PaperMargLft - PaperMargRgt 4.50
PrintHgt = PaperHgt - PaperMargTop - PaperMargBot 3.00

Is anyone willing to write the first draft of the macro?

For now, all of the parameters can be constants in the macro. Later,
we can get them from the user. The PageHgt & PageWid values can be
obtained from Word.
 
G

Graham Mayor

The problem is related to the printer driver most of which have problems
with custom page sizes in Word, because Word interrogates the printer driver
rather than drives it in order to format the document and it will only
format the document in a manner allowed by the driver. Invariably the driver
will adopt the nearest standard paper size.

The simplest approach is to use a standard paper size (e.g. US Letter) and
set the print area with margins as you have discovered. The following macro
will however apply your values to a new document and you can examine and
experiment with values with
http://www.gmayor.com/BookmarkandVariableEditor.htm

Wouldn't it be simpler to create a template?

Dim oDoc As Document
Dim oVars As Variables
Set oDoc = Documents.Add
Set oVars = oDoc.Variables
With oVars
.Add("PrtrMarg").Value = "0.30"
.Add("PageHgt").Value = PointsToInches(oDoc.PageSetup.PageHeight)
.Add("PageWid").Value = PointsToInches(oDoc.PageSetup.PageWidth)
.Add("PaperHgt").Value = "4.00 "
.Add("PaperWid").Value = "6.00"
.Add("PaperMargTop").Value = "0.50"
.Add("PaperMargBot").Value = "0.50"
.Add("PaperMargLft").Value = "0.75"
.Add("PaperMargRgt").Value = "0.75"
.Add("MargTop").Value = oVars("PageHgt").Value - _
oVars("PaperHgt").Value + _
oVars("PaperMargTop").Value
If oVars("PrtrMarg").Value > oVars("PaperMargBot").Value Then
.Add("MargBot").Value = oVars("PaperMarg").Value
Else
.Add("MargBot").Value = oVars("PaperMargBot").Value
End If
If oVars("PrtrMarg").Value > oVars("PaperMargLft").Value Then
.Add("MargLft").Value = oVars("PtrMarg").Value
Else
.Add("MargLft").Value = oVars("PaperMargLft").Value
End If
.Add("MargRgt").Value = oVars("PageWid").Value - _
oVars("PaperWid") + _
oVars("PaperMargRgt")
.Add("PrintWid").Value = oVars("PaperWid").Value - _
oVars("PaperMargLft").Value - _
oVars("PaperMargRgt").Value
.Add("PrintHgt").Value = oVars("PaperHgt").Value - _
oVars("PaperMargTop").Value - _
oVars("PaperMargBot").Value
End With
With oDoc.PageSetup
.TopMargin = InchesToPoints(oVars("MargTop").Value)
.BottomMargin = InchesToPoints(oVars("MargBot").Value)
.LeftMargin = InchesToPoints(oVars("MargLft").Value)
.RightMargin = InchesToPoints(oVars("MargRgt").Value)
'etc
End With

--
<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
Graham Mayor - Word MVP


<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
 
G

Graham Mayor

It occurred later that if you want to play with the values in the document
you will need a second macro to recalculate and update the pagesetup

Sub Macro2()
Dim oDoc As Document
Dim oVars As Variables
Set oDoc = ActiveDocument
Set oVars = oDoc.Variables
oVars("MargTop").Value = oVars("PageHgt").Value - _
oVars("PaperHgt").Value + _
oVars("PaperMargTop").Value
If oVars("PrtrMarg").Value > oVars("PaperMargBot").Value Then
oVars("MargBot").Value = oVars("PaperMarg").Value
Else
oVars("MargBot").Value = oVars("PaperMargBot").Value
End If
If oVars("PrtrMarg").Value > oVars("PaperMargLft").Value Then
oVars("MargLft").Value = oVars("PtrMarg").Value
Else
oVars("MargLft").Value = oVars("PaperMargLft").Value
End If
oVars("MargRgt").Value = oVars("PageWid").Value - _
oVars("PaperWid") + _
oVars("PaperMargRgt")
oVars("PrintWid").Value = oVars("PaperWid").Value - _
oVars("PaperMargLft").Value - _
oVars("PaperMargRgt").Value
oVars("PrintHgt").Value = oVars("PaperHgt").Value - _
oVars("PaperMargTop").Value - _
oVars("PaperMargBot").Value

With oDoc.PageSetup
.TopMargin = InchesToPoints(oVars("MargTop").Value)
.BottomMargin = InchesToPoints(oVars("MargBot").Value)
.LeftMargin = InchesToPoints(oVars("MargLft").Value)
.RightMargin = InchesToPoints(oVars("MargRgt").Value)
'etc
End With
End Sub


--
<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
Graham Mayor - Word MVP


<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
 
H

Heather Mills

It occurred later that if you want to play with the values in the document
you will need a second macro to recalculate and update the pagesetup

Sub Macro2()
Dim oDoc As Document
Dim oVars As Variables
Set oDoc = ActiveDocument
Set oVars = oDoc.Variables
oVars("MargTop").Value = oVars("PageHgt").Value - _
oVars("PaperHgt").Value + _
oVars("PaperMargTop").Value
If oVars("PrtrMarg").Value > oVars("PaperMargBot").Value Then
oVars("MargBot").Value = oVars("PaperMarg").Value
Else
oVars("MargBot").Value = oVars("PaperMargBot").Value
End If
If oVars("PrtrMarg").Value > oVars("PaperMargLft").Value Then
oVars("MargLft").Value = oVars("PtrMarg").Value
Else
oVars("MargLft").Value = oVars("PaperMargLft").Value
End If
oVars("MargRgt").Value = oVars("PageWid").Value - _
oVars("PaperWid") + _
oVars("PaperMargRgt")
oVars("PrintWid").Value = oVars("PaperWid").Value - _
oVars("PaperMargLft").Value - _
oVars("PaperMargRgt").Value
oVars("PrintHgt").Value = oVars("PaperHgt").Value - _
oVars("PaperMargTop").Value - _
oVars("PaperMargBot").Value

With oDoc.PageSetup
.TopMargin = InchesToPoints(oVars("MargTop").Value)
.BottomMargin = InchesToPoints(oVars("MargBot").Value)
.LeftMargin = InchesToPoints(oVars("MargLft").Value)
.RightMargin = InchesToPoints(oVars("MargRgt").Value)
'etc
End With
End Sub

Thank you very, very much. This will take me awhile to study. I'll be
back...;-)
 
H

Heather Mills

The problem is related to the printer driver most of which have problems
with custom page sizes in Word, because Word interrogates the printer driver
rather than drives it in order to format the document and it will only
format the document in a manner allowed by the driver. Invariably the driver
will adopt the nearest standard paper size.

The simplest approach is to use a standard paper size (e.g. US Letter) and
set the print area with margins as you have discovered. The following macro
will however apply your values to a new document and you can examine and
experiment with values with
http://www.gmayor.com/BookmarkandVariableEditor.htm

Wouldn't it be simpler to create a template?

Dim oDoc As Document
Dim oVars As Variables
Set oDoc = Documents.Add
Set oVars = oDoc.Variables

I am trying to figure out what this macro does. Can you recommend
either a website or a book where I can look up statements like the
above -- like a language reference?

I searched the VBA help but couldn't find what the "As Document" and
"As Variables" clauses did. The help text for the Dim statement has
this for the Type keyword:

"Optional. Data type of the variable; may be Byte, Boolean, Integer,
Long, Currency, Single, Double, Decimal (not currently supported),
Date, String (for variable-length strings), String * length (for
fixed-length strings), Object, Variant, a user-defined type, or an
object type. Use a separate As type clause for each variable you
declare."

I assume that these are object types, but that doesn't tell me what
they *do*.
 
J

Jay Freedman

To take the Document example you mentioned, you're correct that using "As Document" in a Dim statement declares the variable to be of an object type -- specifically, a Document object.

Once you've declared a Document type of variable in a Dim statement, you can then use a Set statement to assign a particular document to that variable, in this case

Set oDoc = Documents.Add

A Document object is a representation of an entire Word document. This type of object has "members" (that is, properties and methods) that let you format, insert into, delete from, and otherwise
manipulate that document. To see a list of all the members, press F2 in the VBA editor to open the Object Browser, then select Document in the left-hand list. The members will be shown in the
right-hand list, and you can click on any one of them and press F1 to get its Help topic.

Similarly, declaring a variable "As Variable" makes it an object of Variable type. Unfortunately there are two separate meanings of "variable" in that sentence -- the lower-case "variable" means a
variable (memory location) within the macro, while the capitalized "Variable" means a "document variable" that is stored in the document and can be displayed by a DOCVARIABLE field. Again, you can
look at the Object Browser to see the members of the Variable object.
 
H

Heather Mills

The problem is related to the printer driver most of which have problems
with custom page sizes in Word, because Word interrogates the printer driver
rather than drives it in order to format the document and it will only
format the document in a manner allowed by the driver. Invariably the driver
will adopt the nearest standard paper size.

The simplest approach is to use a standard paper size (e.g. US Letter) and
set the print area with margins as you have discovered. The following macro
will however apply your values to a new document and you can examine and
experiment with values with
http://www.gmayor.com/BookmarkandVariableEditor.htm

Graham,

I got the macro mostly working. The code is posted below. It correctly
calculates the margin settings for the given paper size and sets them
in the document.

The only problem is that it does it is a new document, not the active
document. I think this is because of the "Set oDoc = Documents.Add"
statement. Following Jay's instructions, I looked at the other members
of this object, but didn;t see amny that looked like it would select
the active document.

What statement do I use to set the oDoc variable to the active
document?




Here's my code so far:


Sub MyCustomPageSize()

' Custom form page parameters
Const FPageWid = 7: Const FPageHgt = 4
Const FMargLft = 0.75: Const FMargRgt = 0.75
Const FMargTop = 0.5: Const FMargBot = 0.5

' Word page dimensions
Const WPageWid = 8.5: Const WPageHgt = 11

' Printer no-print area
Const PNoPrTop = 0.25: Const PNoPrBot = 0.25
Const PNoPrLft = 0.25: Const PNoPrRgt = 0.25

Dim WMargTop, WMargBot, WMargLft, WMargRgt ' Word margins
WMargTop = FMargTop
WMargBot = WPageHgt - FPageHgt + FMargBot
WMargLft = FMargLft
WMargRgt = WPageWid - FPageWid + FMargRgt

Dim oDoc As Document
Dim oVars As Variables
Set oDoc = Documents.Add
Set oVars = oDoc.Variables

With oVars
.Add("WMargTop").Value = WMargTop
.Add("WMargBot").Value = WMargBot
.Add("WMargLft").Value = WMargLft
.Add("WMargRgt").Value = WMargRgt
End With

With oDoc.PageSetup
.TopMargin = InchesToPoints(oVars("WMargTop").Value)
.BottomMargin = InchesToPoints(oVars("WMargBot").Value)
.LeftMargin = InchesToPoints(oVars("WMargLft").Value)
.RightMargin = InchesToPoints(oVars("WMargRgt").Value)
End With

End Sub
 
G

Graham Mayor

Change
Set oDoc = Documents.Add
to
Set oDoc = ActiveDocument

if you want to process the active document, but then you may need to add
extra error trapping to ensure that it is the correct document or indeed if
there is a document open.


--
<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
Graham Mayor - Word MVP


<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
 
H

Heather Mills

Change
Set oDoc = Documents.Add
to
Set oDoc = ActiveDocument

That worked perfectly. Thanks.
if you want to process the active document, but then you may need to add
extra error trapping to ensure that it is the correct document or indeed if
there is a document open.

I'll think about that later. I just need to get this project done.


Now I'm getting an error on the .Add statement:

.Add("WMargTop").Value = WMargTop

It runs correctly once, but complains if I rerun it. I suspect I need
to drop a variable or something.

The message is

Run-time error '5903':

The variable name already exists.
 
H

Heather Mills

That worked perfectly. Thanks.


I'll think about that later. I just need to get this project done.


Now I'm getting an error on the .Add statement:

.Add("WMargTop").Value = WMargTop

It runs correctly once, but complains if I rerun it. I suspect I need
to drop a variable or something.

The message is

Run-time error '5903':

The variable name already exists.

After a little fiddling around, I came up with this, which seems to
work:

With oVars
.Item("WMargTop").Delete
.Item("WMargBot").Delete
.Item("WMargLft").Delete
.Item("WMargRgt").Delete
End With
 
H

Heather Mills

On Wed, 5 Jan 2011 12:59:26 +0200, "Graham Mayor"

Since I always want to work on the active document, can I replace all
of the oDoc and oVar code with soemthing like this:

With ActiveDocument
.PageSetup.TopMargin = InchesToPoints(WMargTop)
.PageSetup.BottomMargin = InchesToPoints(WMargBot)
.PageSetup.LeftMargin = InchesToPoints(WMargLft)
.PageSetup.RightMargin = InchesToPoints(WMargRgt)
End With

It seems to work the same and there are no document variables to
create and delete.

Any drawbacks?
 
H

Heather Mills

To take the Document example you mentioned, you're correct that using "As Document" in a Dim statement declares the variable to be of an object type -- specifically, a Document object.

Once you've declared a Document type of variable in a Dim statement, you can then use a Set statement to assign a particular document to that variable, in this case

Set oDoc = Documents.Add

A Document object is a representation of an entire Word document. This type of object has "members" (that is, properties and methods) that let you format, insert into, delete from, and otherwise
manipulate that document. To see a list of all the members, press F2 in the VBA editor to open the Object Browser, then select Document in the left-hand list. The members will be shown in the
right-hand list, and you can click on any one of them and press F1 to get its Help topic.

Similarly, declaring a variable "As Variable" makes it an object of Variable type. Unfortunately there are two separate meanings of "variable" in that sentence -- the lower-case "variable" means a
variable (memory location) within the macro, while the capitalized "Variable" means a "document variable" that is stored in the document and can be displayed by a DOCVARIABLE field. Again, you can
look at the Object Browser to see the members of the Variable object.

Thanks for that little tutorial. Very helpful. Hugs.
 
G

Graham Mayor

You get the variable error because you have already run the macro on the
document and created the variables.
Adding
On Error Resume Next
before
With oVars
.Add("WMargTop").Value = WMargTop
.Add("WMargBot").Value = WMargBot
.Add("WMargLft").Value = WMargLft
.Add("WMargRgt").Value = WMargRgt
End With
would prevent the error from trying to add them a second time in that
document
The macro should surely only be run once - and not at all if you setup a
template with the required settings.
--
<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
Graham Mayor - Word MVP


<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
 
G

Graham Mayor

Yes that should work.

--
<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
Graham Mayor - Word MVP


<>>< ><<> ><<> <>>< ><<> <>>< <>><<>
 

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