Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Create headers and footers of all three types 1

Status
Not open for further replies.

lbenson

Programmer
Dec 14, 2007
3
I'm trying to programmatically add different headers and footers of all three types (Primary, FirstPage, EvenPages) to sections of a document. I am trying to test code which I have found on the web, but when I run the following sub in Word--using a fresh document with nothing in it--all I get is a header and footer (no variation when I add more pages) which says, "Error! Bookmark not defined." What do I need to do to get this sample to work with different headers and footers on first, even, and odd pages?

Sub TestSecHdr3()
With ActiveDocument.Sections(1)
.Headers(wdHeaderFooterFirstPage).Range.Delete
.Headers(wdHeaderFooterPrimary).Range.Delete
.Headers(wdHeaderFooterEvenPages).Range.Delete
.Footers(wdHeaderFooterFirstPage).Range.Delete
.Footers(wdHeaderFooterPrimary).Range.Delete
.Footers(wdHeaderFooterEvenPages).Range.Delete
ActiveDocument.Fields.Add _
Range:=.Headers(wdHeaderFooterFirstPage).Range, Type:=wdFieldEmpty, Text:="Header First"
ActiveDocument.Fields.Add _
Range:=.Headers(wdHeaderFooterPrimary).Range, Type:=wdFieldEmpty, Text:="Header Odd"
ActiveDocument.Fields.Add _
Range:=.Headers(wdHeaderFooterEvenPages).Range, Type:=wdFieldEmpty, Text:="Header Even"
ActiveDocument.Fields.Add _
Range:=.Footers(wdHeaderFooterFirstPage).Range, Type:=wdFieldEmpty, Text:="Footer First"
ActiveDocument.Fields.Add _
Range:=.Footers(wdHeaderFooterPrimary).Range, Type:=wdFieldEmpty, Text:="Footer Odd"
ActiveDocument.Fields.Add _
Range:=.Footers(wdHeaderFooterEvenPages).Range, Type:=wdFieldEmpty, Text:="Footer Even"
End With
End Sub
 
1. why are you adding Fields with text? Is there a specific reason for doing this? A field with "Header First" is not meaningful. Which is why you get the Error! Bookmark not defined. Fields either have meaningful content themselves (eg. DATE, AUTHOR etc.), or they point to something that does (eg. REF - a bookmark or another field)

2. while the header and footer objects are there for each Section, unless you set the layout of the Section for DifferentFirstPage, and DifferentOddEven you will not see them.

3. your code could run more efficiently. You have:
Code:
With ActiveDocument.Sections(1)
.Headers(wdHeaderFooterFirstPage).Range.Delete
.Headers(wdHeaderFooterPrimary).Range.Delete
.Headers(wdHeaderFooterEvenPages).Range.Delete
.Footers(wdHeaderFooterFirstPage).Range.Delete
.Footers(wdHeaderFooterPrimary).Range.Delete
.Footers(wdHeaderFooterEvenPages).Range.Delete

Here is the same effect:
Code:
Dim ThisDoc As Document
Dim var
Set ThisDoc = ActiveDocument
For var = 1 To 3
    ThisDoc.Sections(1).Headers(var).Range.Delete
    ThisDoc.Sections(1).Footers(var).Range.Delete
Next var

Just to be clear, Primary = 1, FirstPage = 2, OddEven = 3. So you can run 1 To 3 (as var) to do your deletes.

You could also do it like this:
Code:
Dim ThisDoc As Document
Dim oHF As HeaderFooter
Set ThisDoc = ActiveDocument
For Each oHF in ThisDoc.Section(1).Headers
   oHF.Range.Delete
Next
For Each oHF in ThisDoc.Section(1).Footers
   oHF.Range.Delete
Next
Or even like this, using a Section object:
Code:
Dim oSection As Section
Dim oHF As HeaderFooter
Set oSection = ActiveDocument.Sections(1)
For Each oHF in oSection.Headers
   oHF.Range.Delete
Next
For Each oHF in oSection(1).Footers
   oHF.Range.Delete

If you just want to have the text you are putting into the empty fields ("Header First", "Footer First"....etc.), then the whole thing could look like:
Code:
Sub HeaderFooterStuff()
Dim ThisDoc As Document
Dim oHF As HeaderFooter
Dim var
Set ThisDoc = ActiveDocument
For var = 1 To 3
    ThisDoc.Sections(1).Headers(var).Range.Delete
    ThisDoc.Sections(1).Footers(var).Range.Delete
Next var

With ThisDoc.PageSetup
    .DifferentFirstPageHeaderFooter = True
    .OddAndEvenPagesHeaderFooter = True
End With

With ThisDoc.Sections(1)
    For var = 1 To 3
        Set oHF = .Headers(var)
        Select Case var
            Case 1 ' Primary
                oHF.Range.Text = "Header Odd"
            Case 2 ' FirstPage
                oHF.Range.Text = "Header First"
            Case 3 ' OddEven
                oHF.Range.Text = "Header Even"
        End Select
        
        Set oHF = .Footers(var)
        Select Case var
            Case 1 ' Primary
                oHF.Range.Text = "Footer Odd"
            Case 2 ' FirstPage
                oHF.Range.Text = "Footer First"
            Case 3 ' OddEven
                oHF.Range.Text = "Footer Even"
        End Select
    Next
End With
End Sub
The HeaderFooter object oHF is used first as a header, then as a footer, in the Select Case statements. The Select Case simply gets the value of var ( 1, 2, 3) and uses that with the header (or footer) object to insert text.

You can make it even shorter and more efficient if you use arrays of text, like this:
Code:
Sub AnotherWay()
Dim ThisDoc As Document
Dim oHF As HeaderFooter
Dim var
Dim HeaderText()
Dim FooterText()
HeaderText = Array("Header Odd", "Header First", "Header Even")
FooterText = Array("Footer Odd", "Footer First", "Footer Even")
Set ThisDoc = ActiveDocument

With ThisDoc.PageSetup
    .DifferentFirstPageHeaderFooter = True
    .OddAndEvenPagesHeaderFooter = True
End With

For var = 1 To 3
    ThisDoc.Sections(1).Headers(var).Range.Delete
    ThisDoc.Sections(1).Footers(var).Range.Delete
Next var

With ThisDoc.Sections(1)
    For var = 1 To 3
            .Headers(var).Range.Text = HeaderText(var - 1)
            .Footers(var).Range.Text = FooterText(var - 1)
    Next
End With
End Sub
The first var loop deletes everything. The second inserts text into BOTH headers and footers using the appropriate text array. You do, of course, have to make sure the text array items are in the correct order.


But again, what exactly is your intention using an empty field and putting text like "Header First" into it?

faq219-2884

Gerry
My paintings and sculpture
 
Garry,

Thank you very much. I need to study your code to see what else I can learn from it, but you solved my immediate problem with this suggestion:

"while the header and footer objects are there for each Section, unless you set the layout of the Section for DifferentFirstPage, and DifferentOddEven you will not see them"

and this code:

ActiveDocument.PageSetup.DifferentFirstPageHeaderFooter = True
ActiveDocument.PageSetup.OddAndEvenPagesHeaderFooter = True

By putting those two lines in front of the original code I had tested (not what was shown in my post--which, as it turns out was around the barn and not close to accomplishing what I wanted), all worked to give me First, Even, and Odd Headers and Footers.

My code now, which works on a new blank document, is as follows:

ActiveDocument.PageSetup.DifferentFirstPageHeaderFooter = True
ActiveDocument.PageSetup.OddAndEvenPagesHeaderFooter = True
ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).LinkToPrevious = False
ActiveDocument.Sections(1).Headers(wdHeaderFooterFirstPage).LinkToPrevious = False
ActiveDocument.Sections(1).Headers(wdHeaderFooterEvenPages).LinkToPrevious = False
ActiveDocument.Sections(1).Footers(wdHeaderFooterPrimary).LinkToPrevious = False
ActiveDocument.Sections(1).Footers(wdHeaderFooterFirstPage).LinkToPrevious = False
ActiveDocument.Sections(1).Footers(wdHeaderFooterEvenPages).LinkToPrevious = False
ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).Range.Text = "Section 1 Primary (Odd) header"
ActiveDocument.Sections(1).Headers(wdHeaderFooterFirstPage).Range.Text = "Section 1 First header"
ActiveDocument.Sections(1).Headers(wdHeaderFooterEvenPages).Range.Text = "Section 1 Even header"
ActiveDocument.Sections(1).Footers(wdHeaderFooterPrimary).Range.Text = "Section 1 Primary (Odd) Footer"
ActiveDocument.Sections(1).Footers(wdHeaderFooterFirstPage).Range.Text = "Section 1 First Footer"
ActiveDocument.Sections(1).Footers(wdHeaderFooterEvenPages).Range.Text = "Section 1 Even Footer"

Your points about using the "with" clauses and 1, 2, and 3 as indexes for "Primary", "First", and "Even" are taken--for the purpose of my understanding, I have made all explicit. What are shown above are, of course, not the real headers and footers I will be using--they are intended to enable me to confirm that I have what I want where I want it.

 
Your points about using the "with" clauses and 1, 2, and 3 as indexes for "Primary", "First", and "Even" are taken--for the purpose of my understanding, I have made all explicit
Ummmm, using With still makes them explicit. How could it not be explicit? You are most certainly NOT making them any more explicit by writing them out as separate instructions. Although, I think I understand what you are getting at.


However, you gain nothing by using separate instructions. You gain nothing by separating out the LinkToPrevious instructions from the Range.Text instructions. Nothing...at least code wise. In fact, in a wee technical way, you lose. The VBA parser must parse more instructions.

Hopefully, when you finish this up you will put the LinkToPrevious with all the other instructions PER headerfooter.
Code:
Dim oSection As Section
For Each oSection In ActiveDocument.Sections
   For var = 1 To 3
      oSection.Headers(var).LinkToPrevious = False
         ' your header text code
      oSection.Footers(var).LinkToPrevious = False
         ' your footer text code
   Next
Next

is much clearer to read - and write - than:
Code:
 ActiveDocument.Sections(1).Headers(wdHeaderFooterPrimary).LinkToPrevious = False
  ActiveDocument.Sections(1).Headers(wdHeaderFooterFirstPage).LinkToPrevious = False
  ActiveDocument.Sections(1).Headers(wdHeaderFooterEvenPages).LinkToPrevious = False
  ActiveDocument.Sections(1).Footers(wdHeaderFooterPrimary).LinkToPrevious = False
  ActiveDocument.Sections(1).Footers(wdHeaderFooterFirstPage).LinkToPrevious = False
  ActiveDocument.Sections(1).Footers(wdHeaderFooterEvenPages).LinkToPrevious = False

Not only that, but the code above will only action Section 1 because it does it as separate instructions. The code using the variable will do it for ALL sections.

In your OP, you only mentioned a Section 1. Therefore I did not put anything in regarding LinkToPrevious. However, it is good that you do add it. LinkToPrevious is the property that, by far, messes people up with headers and footers. If your document is going to have more than one Section, you must pay attention to LinkToPrevious. Good on you. I would say you understand pretty well. In particular, you have it bang on that you must do any LinkToPrevious = False before you put content into headers or footers.

Just one big hint. Word moves the header/footer content backwards through the document. It is part of the way Microsoft conceives a DOCUMENT.

Say you have (and for simplicity let's just do headers) a document with three Sections. All the LinkToPrevious are correct, and you have DifferentFirstPage and DifferentOddEven = True. The header text looks like this:

"Section 1 First Page" (#1)
"Section 1 Even Page" (#2)
"Section 1 Odd Page" (#3)
"Section 2 First Page" (#4)
"Section 2 Odd Page" (#5)
"Section 2 Even Page" (#6)
"Section 3 First Page" (#7)
"Section 3 Even Page" (#8)
"Section 3 Odd Page" (#9)

OK?

If you delete the Section breaks - NOT any pages, just the Section breaks - you end up with one Section. Section 1.

Right?

What will the text be?

It will be:

"Section 3 First Page" (#1)
"Section 3 Even Page" (#2)
"Section 3 Odd Page" (#3)
"Section 3 Even Page" (#4)
"Section 3 Odd Page" (#5)
"Section 3 Even Page" (#6)
"Section 3 Odd Page" (#7)
"Section 3 Even Page" (#8)
"Section 3 Odd Page" (#9)

Word will not, repeat NOT, retain what you put in as text in Section 1.

Let's do it again.

"Section 1 First Page" (#1)
"Section 1 Even Page" (#2)
"Section 1 Odd Page" (#3)
"Section 2 First Page" (#4)
"Section 2 Odd Page" (#5)
"Section 2 Even Page" (#6)
"Section 3 First Page" (#7)
"Section 3 Even Page" (#8)
"Section 3 Odd Page" (#9)

Now, this time, just remove the Section break for Section 3. Again, no changes to the pages, just the Section break. There are now two Sections - Section 1 and Section 2.

What will the text be? It will be:

"Section 1 First Page" (#1)
"Section 1 Even Page" (#2)
"Section 1 Odd Page" (#3)
"Section 3 First Page" (#4)
"Section 3 Odd Page" (#5)
"Section 3 Even Page" (#6)
"Section 3 Odd Page" (#7)
"Section 3 Even Page" (#8)
"Section 3 Odd Page" (#9)

Word moves header (and footer) content backwards through the document with deletions. Once set, the LAST Section content will always be the LAST Section content. No matter what the index number is.

In the first example (now only ONE Section, Section 1), the section headers content is the LAST Section content - ie. Section 3.

In the second example (two Sections, Section 1 and 2), the LAST Section still retains the LAST Section content - ie. Section 3

Even though Section 3 no longer exists. Do not get fooled into thinking header (or footer) text content is directly connected to the Section.

On the other hand, it is also important to note that ANY content, once set into a headerfooter, persists. If you:

DifferentFirstPage = True (checked in Page Setup)
Put "Section 1 First Page" in as text.

Then DifferentFirstPage = False (unchecked in Page Setup)

The text "Section2 First Page" persists. If you make DifferentFirstPage True again, that text will be there. So be careful if you use .Exists for headers or footers. Take the example above. DifferentFirstPage was set as True, text put into the header, then set as False. There is NO different first page. Run the following code.
Code:
Sub CheckIf()
If ActiveDocument.Sections(1).Headers(2).Exists = True Then
    MsgBox "True"
Else
    MsgBox "False"
End If
MsgBox ActiveDocument.Sections(1).Headers(2).Range.Text
End Sub
It checks to see if DifferentFirstPage "exists". DifferentFirstPage is currently NOT checked, so .Exists will return a "False" message.....then display the text of that supposed non-existing thing.

The .Exists property does NOT check the content of the header. It checks whether Page Setup is True or False. NOT the header...because....

The headers and footers themselves (Primary, FirstPage, EvenPages) always exist. You can not delete them.

Have fun.

faq219-2884

Gerry
My paintings and sculpture
 
Garry,

Thanks again for the very detailed explanation. I agree that the long form of the statements which I wrote is no more explicit in the sense of providing instructions of what to do, but it can be, I find, easier on the unexperienced programmer to unwind the "with" clauses and the "For Each" clauses. For this particular code, time of execution will not be significant. But again I take your point about good practice, and I do use indexing to provide generality (I took it out in posting the above code).

I will have different headers and mostly different footers for each of many sections in the document. Thanks for your explanation of the effect of Microsoft's "look-back" header/footer view on the deleting of sections. Fortunately, once I have finished re-formatting this non-WYSIWYG marked-up 80s-style document, I won't have to deal with formatting it on an ongoing basis. But I may be able to explain the effects to someone who does edit it.
 
this non-WYSIWYG marked-up 80s-style document"

Thanks for the laugh. I hear you. Been there. Done that.

All the best. Updating those can be a pain.

faq219-2884

Gerry
My paintings and sculpture
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top