The Anchorage
Personal website of Gregory K. Maxey, Commander USN (Retired)
The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.
However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.
If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!
This Microsoft Word Tips & Microsoft Word Help page provides a couple of solutions to the frequently asked question, "How do I prevent the placeholder text (PHT) in uncompleted content controls from printing?" The solutions provided are a result of collaborative effort with MVP Jay Freedman.
The problem can occur often. You prepare a form and send it out for completion. Users complete part of the form and leave some of the content controls uncompleted. When the form is returned and printed the PHT in the uncompleted content controls are printed. This results in an unsightly finished form.
Unfortunately there isn't a simple solution. There is no option in Word to exclude printing content control PHT, and without an intensive form validation process, you can't make the user fill out each field.
Each of the automated solutions provided require VBA which means the template and form documents must be macro enabled (i.e., .dotm and .docm extensions).
The first method employs the application event "DocumentBeforePrint," repurposed Print commands and a temporary modification of the document's Placeholder text style.
Placeholder text, like most text in Word, is defined by a style. If you temporarily set the Placeholder text style font property .Hidden to true, set the application options .PrintHiddenText property to false and print the document the PHT text will not be printed. This can of course be done manually if you have a willing group of form users, but an automated process requires a VBA solution.
Notes:
1. The Normal project is project associated with the Normal template. It is global and always loaded.
2. The method is developed for Word 2010, but includes all necessary code for Word 2013 and 2007 users. Some elements (e.g., the class module) is not required for Word 2007.
Option Explicit Private WithEvents m_oWordApp As Word.Application Private Sub Class_Initialize() Set m_oWordApp = Word.Application lbl_Exit: Exit Sub End Sub Private Sub m_oWordApp_DocumentBeforePrint(ByVal oDoc As Document, Cancel As Boolean) Dim bOption As Boolean If Not p_bQuickPrint Then If Not p_bInPreviewPrintEditMode Then 'Store current user option setting bOption = Options.PrintHiddenText 'Turn off printing hidden text Options.PrintHiddenText = False 'Modify the placeholder text style ActiveDocument.Styles("Placeholder Text").Font.Hidden = True End If 'Execute the print command CommandBars.ExecuteMso "PrintPreviewAndPrint" 'Pause to allow printer to spool document. Then undo style modification Application.OnTime Now + TimeValue("00:00:05"), "RestorePlaceholders" 'Restore user option Options.PrintHiddenText = bOption 'Return to document CommandBars.ExecuteMso "PrintPreviewAndPrint" End If lbl_Exit: Exit Sub End Sub
Option Explicit Public p_bInPreviewPrintEditMode As Boolean Public p_bQuickPrint As Boolean Private session_clsPrint As clsPrint Private bOption as Boolean Sub AutoExec() 'Initialize variable and class (Word 2010/2013 only) when Word starts p_bQuickPrint = False p_bInPreviewPrintEditMode = False If Application.Version > 12.0 Then Set session_clsPrint = New clsPrint End If lbl_Exit: Exit Sub End Sub Sub RestorePlaceholders() 'Delayed call from class Word 2010/2013 only ActiveDocument.Styles("Placeholder Text").Font.Hidden = False lbl_Exit: Exit Sub End Sub Sub FilePrint() 'Intercepts the Word 2007 Menu>Print>Print command bOption = Options.PrintHiddenText Options.PrintHiddenText = False ActiveDocument.Styles("Placeholder Text").Font.Hidden = True Dialogs(wdDialogFilePrint).Show ActiveDocument.Styles("Placeholder Text").Font.Hidden = False Options.PrintHiddenText = bOption End Sub Sub FilePrintDefault() 'Intercepts the Word 2007/2010/2013 Quick Print commands 'Prevent triggering a duplicate print in the class modules (Word 2010/2013) p_bQuickPrint = True If Not p_bInPreviewPrintEditMode Then bOption = Options.PrintHiddenText Options.PrintHiddenText = False ActiveDocument.Styles("Placeholder Text").Font.Hidden = True ActiveDocument.PrintOut Background:=False ActiveDocument.Styles("Placeholder Text").Font.Hidden = False Options.PrintHiddenText = bOption Else ActiveDocument.PrintOut Background:=False End If p_bQuickPrint = False lbl_Exit: Exit Sub End Sub Sub PrintPreviewEditMode() 'Intercepts the Word 2010 Print Preview/2013 Edit Mode If p_bInPreviewPrintEditMode Then 'User likely was in PPEM then used PPPM but didn't print. PHT already modified ActiveDocument.PrintPreview Else p_bInPreviewPrintEditMode = True bOption = Options.PrintHiddenText Options.PrintHiddenText = False ActiveDocument.Styles("Placeholder Text").Font.Hidden = True ActiveDocument.PrintPreview Options.PrintHiddenText = bOption End If lbl_Exit: Exit Sub End Sub Sub FilePrintPreview() 'Intercepts the Word 2007 Print Preview command bOption = Options.PrintHiddenText Options.PrintHiddenText = False ActiveDocument.Styles("Placeholder Text").Font.Hidden = True ActiveDocument.PrintPreview Options.PrintHiddenText = bOption lbl_Exit: Exit Sub End Sub Sub ClosePreview() ActiveDocument.Styles("Placeholder Text").Font.Hidden = False p_bInPreviewPrintEditMode = False On Error GoTo lbl_Exit ActiveDocument.ClosePrintPreview lbl_Exit: Exit Sub End Sub
Note: You have to close and restart Word in order fo the AutoExec macro to initialize the clsPrint class.
The following is an explanation of how the process more or less works:
Notes:
1. If you often print large forms, you may want to increase the delay. This delay is needed because changing the Hidden attribute immediately (at the end of the DocumentBeforePrint routine) would happen before the PrintPreviewAndPrint command
has time to spool the content to the printer queue.
2. Due to a plethora of complications associated the inability to intercept the PrintPreviewAndPrint command, the PHT will still appear visible in the backstage preview pane when you select the File tab in Word 2010/2013, but that visible PHT IS NOT printed.
3. If you really want to see what the document will look like with PHT suppressed then add the PrintPreviewAndEdit control to your QAT. In Print Preview and Edit mode, the PHT is suppressed.
4. If while in the Print Preview and Edit mode you select the Print Preview and Print control the backstage view and preview appears with the PHT suppressed.
5. If you print (i.e, select the "Print" command) the PHT is suppressed in the printed document and then restored after the short delay.
6. However, if you don't print and return to the document by clicking one of the other tabs on the ribbon then the PHT will not be restored and remain formatted as hidden text.
7. In this situation, you can restore PHT by immediately switching to Print Preview and Edit mode then closing the mode.
The second method, similar to the first, employs the application event "DocumentBeforePrint," repurposed Print commands and a temporary alteration of the PHT object itself.
Placeholder text, is a bit peculiar. While it appears to be text, a content control's .PlaceholderText property is actually a Building Block object with a value. For a more in depth discussion see: 5 Curiosities about Placeholders in Word Content Controls (for developers). If we temporarily set the .PlaceholderText property to a zero width space (i.e., ChrW(8203), before printing and restore then original PHT after printing the results will be similar to method I. The code is a bit more complicated and the only advantage is we don't tinker with user options or restrict printing of hidden text in general.
The jury is still deliberating if there is any real advantage over either method, but I use method II in my Content Control Tools Add-In. So here it is:
Note: If you have already created the modules using method I then simply delete the existing content in the modules. Do not attempt to use both methods simultaneously.
Option Explicit Private WithEvents m_oWordApp As Word.Application Private Sub Class_Initialize() Set m_oWordApp = Word.Application End Sub Private Sub m_oWordApp_DocumentBeforePrint(ByVal Doc As Document, Cancel As Boolean) If Not p_bQuickPrint Then If Not p_bInPreviewPrintEditMode Then 'Call procedures in the standard module to alter placeholder text modPrint.DimensionArray modPrint.Processor 2 End If 'Execute the print command CommandBars.ExecuteMso "PrintPreviewAndPrint" 'Pause to allow printer to spool document. Then call procedure to restore placeholder DoEvents Application.OnTime Now + TimeValue("00:00:05"), "modPrint.RestorePHT" 'Toggle back to document CommandBars.ExecuteMso "PrintPreviewAndPrint" End If lbl_Exit: Exit Sub End Sub
Option Explicit Public p_bInPreviewPrintEditMode As Boolean Public p_bQuickPrint As Boolean Private session_clsPrint As clsPrint Private oRngStory As Word.Range Private lngValidator As Long Private oCC As ContentControl Private oShp As Shape Private arrPHT() As String Private i As Long Public Type CCCollection Count As Long bContainsCCs As Boolean End Type Private m_bModifiedCCs As Boolean Sub AutoExec() 'Initialize variables and class when Word starts p_bQuickPrint = False p_bInPreviewPrintEditMode = False If Application.Version > 12# Then Set session_clsPrint = New clsPrint End If lbl_Exit: Exit Sub End Sub Sub DimensionArray() 'Count CCs in document i = Processor(1).Count ReDim arrPHT(i) lbl_Exit: Exit Sub End Sub Sub RestorePHT() 'Called from clsPrint modPrint.Processor 3 lbl_Exit: Exit Sub End Sub Sub FilePrint() 'Intercepts the Word 2007 Menu>Print>Print command 'Call procedures alter placeholder text DimensionArray Processor 2 Dialogs(wdDialogFilePrint).Show 'Call procedures to restore placeholder text Processor 3 lbl_Exit: Exit Sub End Sub Sub FilePrintDefault() 'Intercepts the Word 2007/2010/2013 Quick Print commands p_bQuickPrint = True If Not p_bInPreviewPrintEditMode Then 'Call procedures alter placeholder text DimensionArray Processor 2 'Print the document ActiveDocument.PrintOut 'Call procedures to restore placeholder text Processor 3 Else ActiveDocument.PrintOut End If p_bQuickPrint = False lbl_Exit: Exit Sub End Sub Sub PrintPreviewEditMode() 'Intercepts the Wor 2010 PrintPreviewEditMode command If p_bInPreviewPrintEditMode Then 'User likely was in PPEM then used PPPM but didn't print ActiveDocument.PrintPreview Else p_bInPreviewPrintEditMode = True m_bModifiedCCs = False DimensionArray If Processor(2).bContainsCCs = True Then m_bModifiedCCs = True End If ActiveDocument.PrintPreview End If If m_bModifiedCCs Then Application.StatusBar = "CC PHT modified" lbl_Exit: Exit Sub End Sub Sub FilePrintPreview() 'Intercepts the Word 2007 PrintPreview command m_bModifiedCCs = False DimensionArray If Processor(2).bContainsCCs = True Then m_bModifiedCCs = True End If ActiveDocument.PrintPreview If m_bModifiedCCs Then Application.StatusBar = "CC PHT modified" lbl_Exit: Exit Sub End Sub Sub ClosePreview() p_bInPreviewPrintEditMode = False Processor 3 On Error GoTo lbl_Exit ActiveDocument.ClosePrintPreview lbl_Exit: On Error GoTo 0 Exit Sub End Sub Function Processor(ByRef lngAction As Long) As CCCollection Dim oCount As Long i = 0 lngValidator = ActiveDocument.Sections(1).Headers(1).Range.StoryType For Each oRngStory In ActiveDocument.StoryRanges 'Iterate through all linked stories Select Case oRngStory.StoryType Case 1 To 11 Do For Each oCC In oRngStory.ContentControls Select Case lngAction Case 1 oCount = oCount + 1 Case 2 oCount = oCount + 1 'Store placeholder text arrPHT(i) = oCC.PlaceholderText 'Set temporary placeholder text oCC.SetPlaceholderText , , ChrW(8203) i = i + 1 Case 3 If oCC.ShowingPlaceholderText Then 'Restore stored placeholder text oCC.SetPlaceholderText , , arrPHT(i) End If i = i + 1 End Select Next oCC Select Case oRngStory.StoryType Case 6, 7, 8, 9, 10, 11 If oRngStory.ShapeRange.Count > 0 Then For Each oShp In oRngStory.ShapeRange On Error GoTo Err_HasText If oShp.TextFrame.HasText Then For Each oCC In oShp.TextFrame.TextRange.ContentControls Select Case lngAction Case 1 oCount = oCount + 1 Case 2 'Store placeholder text arrPHT(i) = oCC.PlaceholderText 'Set temporary placeholder text oCC.SetPlaceholderText , , ChrW(8203) i = i + 1 Case 3 If oCC.ShowingPlaceholderText Then 'Restore stored placeholder text oCC.SetPlaceholderText , , arrPHT(i) End If i = i + 1 End Select Next oCC End If On Error GoTo 0 Err_HasText_ReEntry: Next oShp End If Case Else 'Do Nothing End Select 'Get next linked story (if any) Set oRngStory = oRngStory.NextStoryRange Loop Until oRngStory Is Nothing Case Else End Select Next oRngStory Processor.Count = oCount If oCount > 0 Then Processor.bContainsCCs = True End If Exit Function Err_HasText: Resume Err_HasText_ReEntry End Function
The process and procedures are similar to Method I, instead of changing the PHT style, it:
Method III employs an individual document template, the Document_ContentControlOnEnter & Document_ContentControlOnExit events and custom PHT applied dynamically as the user completes the form.
Option Explicit Private Sub Document_New() ActiveDocument.SelectContentControlsByTitle("Name").Item(1).Range.Select lbl_Exit: Exit Sub End Sub Private Sub Document_Open() ActiveDocument.SelectContentControlsByTitle("Name").Item(1).Range.Select lbl_Exit: Exit Sub End Sub Private Sub Document_ContentControlOnEnter(ByVal ContentControl As ContentControl) Select Case ContentControl.Title Case "Name" ContentControl.SetPlaceholderText , , "Click and enter your name here." Case "Address" ContentControl.SetPlaceholderText , , "Click and enter your address here." Case "Phone Number" ContentControl.SetPlaceholderText , , "Click and enter your phone number here." End Select lbl_Exit: Exit Sub End Sub Private Sub Document_ContentControlOnExit(ByVal ContentControl As ContentControl, Cancel As Boolean) If ContentControl.ShowingPlaceholderText = True Then ContentControl.SetPlaceholderText , , " " End If lbl_Exit: Exit Sub End Sub
Unlike the previous methods, this method has no relationship with the application print processes. It simply uses the built-in document events to dynamically apply or remove a visible placeholder text as the user navigates the form.
Note: This method is the least robust since it is possible that a user enters a CC displaying the visible placeholder text and then prints the document without first exiting the CC. You, or your users, must be sure to physically "exit" any uncompleted document CC.
If properly applied each of the three methods will result in a more appealing printed form.
That's it! I hope you have found this tips page useful and informative.
The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.
However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.
If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!