Word disappearing text - vba

I am currently setting up some MS Word templates in Word 2010 and have encountered a problem, where text suddenly disappears at the end of a paragraph.
The problem only occurs in some specific scenarios, but I have experienced that it can be recreated in a lot of different ways. I have not, however, been able to pinpoint the exact reason why this happens. Therefore, I would like to find the specific reason, that makes the issue occur, in order to avoid it.
It seems that a combination of the existence of wrapped tables, content in the page header and a certain length of a line can invoke the issue.
To recreate a document where this issue occurs, please follow this procedure:
Open a new document in Word 2010.
Copy the code below into a new module in the VBA editor.
Run the A_ReplicateScenario macro to insert example content in the document.
Place the cursor at the end of line 3 (the line that ends close to the margin).
Type a new sentence after the dot, beginning with a space.
The text that you have typed, will disappear when the margin is reached.
The text will then be shown if for instance a character is deleted from the original text (i.e. from the beginning of the line) or if a formatting change is made (e.g. clear formatting). The 'Show all' setting in Word can also sometimes display the text, but will only display it while 'Show all' is activated. Other times Word will display 'ghosted' double lines which can not be selected.
A short video of the replicated issue can be viewed here: https://youtu.be/Bqp9STDRkXc
Sub A_ReplicateScenario()
Call SetUpNormalStyle
Call InsertBodyTextLines
Call InsertHeaderTextLines
Call InsertWrappedTables
Call SetUpMargins
Call InsertExampleBodyText
End Sub
Sub SetUpNormalStyle()
With ActiveDocument.Styles("Normal").Font
.Name = "Arial"
.Size = 10
End With
With ActiveDocument.Styles("Normal").ParagraphFormat
.SpaceAfter = 0
.LineSpacingRule = wdLineSpaceAtLeast
.LineSpacing = 12
End With
End Sub
Sub InsertBodyTextLines()
For i = 1 To 4
Selection.TypeParagraph
Next
End Sub
Sub InsertHeaderTextLines()
If ActiveWindow.View.SplitSpecial <> wdPaneNone Then
ActiveWindow.Panes(2).Close
End If
If ActiveWindow.ActivePane.View.Type = wdNormalView Or ActiveWindow. _
ActivePane.View.Type = wdOutlineView Then
ActiveWindow.ActivePane.View.Type = wdPrintView
End If
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
For i = 1 To 26
Selection.TypeParagraph
Next
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
End Sub
Sub InsertWrappedTables()
Selection.HomeKey Unit:=wdStory
ActiveDocument.Tables.Add Range:=Selection.Range, NumRows:=1, NumColumns:=1, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:=wdAutoFitFixed
With Selection.Tables(1).Rows
.WrapAroundText = True
.HorizontalPosition = CentimetersToPoints(2)
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.VerticalPosition = CentimetersToPoints(4.5)
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
End With
Selection.Tables(1).Columns(1).PreferredWidthType = wdPreferredWidthPoints
Selection.Tables(1).Columns(1).PreferredWidth = CentimetersToPoints(11)
Selection.MoveDown Unit:=wdLine, Count:=1
ActiveDocument.Tables.Add Range:=Selection.Range, NumRows:=1, NumColumns:=1, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:=wdAutoFitFixed
With Selection.Tables(1).Rows
.WrapAroundText = True
.HorizontalPosition = CentimetersToPoints(10)
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.VerticalPosition = CentimetersToPoints(8)
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
End With
Selection.Tables(1).Columns(1).PreferredWidthType = wdPreferredWidthPoints
Selection.Tables(1).Columns(1).PreferredWidth = CentimetersToPoints(9)
End Sub
Sub SetUpMargins()
With ActiveDocument.PageSetup
.TopMargin = CentimetersToPoints(3.8)
.BottomMargin = CentimetersToPoints(2.8)
.LeftMargin = CentimetersToPoints(2.3)
.RightMargin = CentimetersToPoints(1.5)
End With
End Sub
Sub InsertExampleBodyText()
With Selection
.HomeKey Unit:=wdStory
.MoveDown Unit:=wdLine, Count:=3
.TypeText Text:="Ouwouwouwoiwoiuwoiuwoiuwoiuwoiuwoiuwoiw oiwu oiwu owiu woiu woiuw oiwu owiu owiu ww."
.TypeParagraph
.TypeText Text:="Woiuwoiuwoiuw."
End With
End Sub

The problem is related to the tables being formatted to float around the text. Word has a long history of issues with floating objects. And although Word has improved a lot over the years you might still experience problems, in particular with floating tables.
If you change the formatting of the second table (via Table Properties) and set the text wrapping to None, the bug goes away (YMMV).
My recommendation would be to avoid the floating tables if possible.

Related

Run-time error 4198, command failed, when trying to set ms word doc to print view

I am trying to set the window view to printView.
I've used the "record macro" in word, to see how word suggests I set something to print view. Here's the code:
If ActiveWindow.View.SplitSpecial = wdPaneNone Then
ActiveWindow.ActivePane.View.Type = wdPrintView
Else
ActiveWindow.View.Type = wdPrintView
End If
Each time, the execution stops and gives me the above error. The debug points out:
ActiveWindow.View.Type = wdPrintView
as the buggy line. I've also tried:
If ActiveWindow.View.SplitSpecial = wdPaneNone Then
ActiveDocument.ActiveWindow.View.Type = wdPrintView
Else
ActiveWindow.View.SplitSpecial = wdPaneNone
ActiveWindow.View.Type = wdPrintView
End If
The issue seems to happen when the splitspecial is 4 (wdPanePrimaryFooter). But changing the conditional to account for that doesn't seem to work. If I comment out the view type line, everything goes fine.
Any ideas?
Thank you in advance.
Edit, here is the entire block, but I cannot replicate this error half the time:
Sub pageNumber()
ActiveDocument.Sections(ActiveDocument.Sections.Count) _
.Footers(wdHeaderFooterPrimary).Range.Select
With Selection
.ParagraphFormat.Alignment = wdAlignParagraphCenter
.TypeText Text:="Page "
.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
"PAGE ", PreserveFormatting:=True
.TypeText Text:=" of "
.Fields.Add Range:=Selection.Range, Type:=wdFieldEmpty, Text:= _
"NUMPAGES ", PreserveFormatting:=True
.Collapse
End With
ActiveDocument.Content.Select
Selection.Collapse wdCollapseStart
If ActiveWindow.View.SplitSpecial = wdPaneNone Then
ActiveDocument.ActiveWindow.View.Type = wdPrintView
Else
ActiveWindow.View.SplitSpecial = wdPaneNone
ActiveWindow.View.Type = wdPrintView
End If
End Sub
The kind of code in the question is the result of using the macro recorder. This tool is really great, but because it only mimics the user actions, the code it creates is sometimes not optimal. Working with headers and footers, especially, can make life more complicated than it ought to be... When code selects a header/footer range that triggers the display of the old Word 2.0 "panes" that were necessary for editing these. Word 6.0 introduced WYSIWYG and the panes were "retired" and only show up in this context.
When working with headers and footers a Range object is usually preferable than using Selection. You can think of a Range as a invisible selection, with the advantages: 1. It doesn't move the actual selection. 2. There can be as many Range objects as required for the task, while there can be only one selection.
The following code sample gets the Footer range and adds content to it. Since it never changes the selection, the screen is quieter and the pane never shows up (and the code is faster).
Working with ranges is relatively straight-forward, until field codes come into play. Then it takes a bit of work to get the "target" point for new material to follow a field.
Sub pageNumber()
Dim rngFooter As Word.Range
Dim fld As Word.Field
Set rngFooter = ActiveDocument.Sections(ActiveDocument.Sections.Count) _
.Footers(wdHeaderFooterPrimary).Range
With rngFooter
.ParagraphFormat.Alignment = wdAlignParagraphCenter
.Text = "Page "
.Collapse wdCollapseEnd
Set fld = .Fields.Add(Range:=rngFooter, Type:=wdFieldEmpty, Text:= _
"PAGE ", PreserveFormatting:=False)
End With
Set rngFooter = fld.result
With rngFooter
'Move the end of the range outside the field
.MoveStart wdCharacter, 1
.InsertAfter " of "
.Collapse wdCollapseEnd
.Fields.Add Range:=rngFooter, Type:=wdFieldEmpty, Text:= _
"NUMPAGES ", PreserveFormatting:=False
End With
End Sub

Centered Text Box on Each Page in Word

So I am trying to write a code that adds a text box above a table on each page in a word document. This text box is to be centered to align with the table (I have no issues generating a centered table on each page). I have just recently started working in VBA so my knowledge is a little bit lacking. Here is my code so far, it is kind of a mish mash of what I could find online.
Sub TextMaker()
'
' TextMaker Macro
'
'
Dim i As Long, Rng As Range, Shp As Shape
Dim objDoc As Document
Dim objTextBox As Shape
Set objDoc = ActiveDocument
With ActiveDocument
For i = 1 To 5
Set Rng = .GoTo(What:=wdGoToPage, Name:=i)
Set Shp = .Shapes.AddTextbox(Orientation:=msoTextOrientationHorizontal, _
Left:=InchesToPoints(0.1), Top:=InchesToPoints(1.44), Width:=InchesToPoints(7.65), Height:=InchesToPoints(0.29), Anchor:=Rng)
With Shp
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.Left = wdShapeCenter
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Top = InchesToPoints(1.44)
With .TextFrame.TextRange
.Text = "Ref. No.: T" & vbCr & "Signature "
Set Rng = .Paragraphs.First.Range
With Rng
.Font.ColorIndex = wdRed
.End = .End - 1
.Collapse wdCollapseEnd
End With
End With
End With
Next
End With
End Sub
The output works for the first two pages but on the 3rd page the alignment of the text box is not centered. I checked the positioning and the text box still says it is centered relative to page even though it is not.
The code works properly as long as the tables are not inserted, but the table generating code, if run after this one, does not put the tables on the same page as text boxes.
This is the 3rd page of my document, where things start to go wrong. The text box should be positioned above the table and centered in line with it.
In order to reproduce the document, create a blank document and run this table generation code:
Sub TableMaker()
For i = 1 To 5
ActiveDocument.Tables.Add Range:=Selection.Range, NumRows:=6, NumColumns:= _
2, DefaultTableBehavior:=wdWord9TableBehavior, AutoFitBehavior:= _
wdAutoFitFixed
Selection.Tables(1).Columns(1).Width = InchesToPoints(1.39)
Selection.Tables(1).Columns(2).Width = InchesToPoints(6.26)
Selection.Tables(1).Rows.Alignment = wdAlignRowCenter
With Selection.Tables(1).Rows
.WrapAroundText = True
.VerticalPosition = InchesToPoints(1.82)
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.DistanceTop = InchesToPoints(0)
.DistanceBottom = InchesToPoints(0)
.AllowOverlap = False
End With
'place cursor at end of page
Selection.EndKey Unit:=wdStory
'insert page break
Selection.InsertBreak Type:=wdPageBreak
Next i
End Sub
Or run the text generation code above and then this table generation code. Either way the formatting is not consistent. There will be no other text on these documents but an image will be placed below the tables on each page.
The problem is a combination of factors:
the table having text flow formatting. If I set that to "none" the textbox is centered correctly.
if the anchor range is outside the table, it works
I then tested the following and determined that the problem is because "Layout in cell" is activated (thanks for that screen shot BTW). When I put that in (see below) the text box is centered on the page because it's positioning is now independent of the table.
With Shp
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.Left = wdShapeCenter
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Top = InchesToPoints(1.44)
.LayoutInCell = False

How to end a Do Loop in an MS Word macro

I've made a macro to change the header color of a document, but when hitting the end of the document - or if there's no remaining header - I'm getting an error.
What I want is after the last header, at the end of the document, to exit my Do Loop.
Here's my code:
Sub Changecolortest5()
'
' Changecolortest5 Macro
'
'
If ActiveWindow.View.SplitSpecial <> wdPaneNone Then
ActiveWindow.Panes(2).Close
End If
If ActiveWindow.ActivePane.View.Type = wdNormalView Or ActiveWindow. _
ActivePane.View.Type = wdOutlineView Then
ActiveWindow.ActivePane.View.Type = wdPrintView
End If
Do
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader
Selection.MoveDown Unit:=wdParagraph, Count:=1, Extend:=wdExtend
Selection.Font.Color = 8527984
ActiveWindow.ActivePane.View.NextHeaderFooter
Loop
'Exit Header and Footer
ActiveWindow.ActivePane.View.SeekView = wdSeekMainDocument
End Sub
Addressing Headers/Footers optimally doesn't work well with recorded macros, so I'm going to show you a slightly different approach than what you give us. The code below works directly with the underlying objects and applies formatting to the Range rather than a selection. This is faster and the screen doesn't "flicker".
When working with a group of things, such as Headers, it's more usual to use a For-Each loop to cycle through the group. In this case, Headers are specific to Sections, so you loop the Sections. Something along these lines:
Dim doc as Word.Document
Dim sec as Word.Section
Set doc = ActiveDocument
For Each sec in doc.Sections
sec.Headers(wdHeaderFooterPrimary).Range.Paragraphs(1).Range.Font.Color = 8527984
sec.Headers(wdHeaderFooterFirstPage).Range.Paragraphs(1).Range.Font.Color = 8527984
Next
In addition, if you look up the Help topic for Do loops you'll see that they require a test to end the loop: Do While or Do Until or Loop While or Loop Until a certain criterium is met. I'm pretty sure the code you show us must be giving you an error - when asking questions you should always include all relevant information, including any error messages...

Word VBA: Add textboxes with in-line text wrapping to end of document

I'm trying to write a macro which will insert textboxes in a Word document, and format them with in-line-with-text text wrapping.
Here's my code so far:
Sub Example()
Dim newTextbox As Shape
For I = 1 To 10
Set newTextbox = ActiveDocument.Shapes.AddTextbox _
(Orientation:=msoTextOrientationHorizontal, _
Left:=0, Top:=0, Width:=100, Height:=50)
newTextbox.WrapFormat.Type = wdWrapInline
newTextbox.TextFrame.TextRange = I
Next
End Sub
The issue I'm having is that instead of each textbox being added to the start of document, as is currently happening, I need it to be added to the end. I understand that in the example I've given, I could simply use For I = 10 To 1 Step -1. However, due to my use of the textboxes in the actual project I'm working on, this is not possible.
I have spent a few hours playing with the code but just haven't been able to figure it out. Thanks in advance for any help.
Josh.
Joshua, here is a final working code:
Sub InsertInlineTextBox()
' Move all the text after the cursor to a new paragraph
' and jump to the start point of this paragraph
Selection.InsertParagraphAfter
Selection.MoveDown Unit:=wdParagraph, count:=1
Dim aShape As Shape
' Insert the shape at the current cursor position +1 point down in vertical
' direction to prevent automatic moving the shape to the previous paragraph
' during 'inlining'
Set aShape = ActiveDocument.Shapes.AddTextbox( _
msoTextOrientationHorizontal, _
Selection.Information(wdHorizontalPositionRelativeToPage), _
Selection.Information(wdVerticalPositionRelativeToPage) + 1, 400, 60)
With aShape
.TextFrame.MarginBottom = 0 ' adjust text margins
.TextFrame.MarginLeft = 0
.TextFrame.MarginRight = 0
.TextFrame.MarginTop = 0
.Line.Visible = msoFalse ' don't show the border
' converting to InlineShape will place
' the shape at the start point of paragraph
.ConvertToInlineShape
End With
' Remove carriege return before the shape
Selection.EndOf Unit:=wdParagraph, Extend:=wdMove
Selection.MoveLeft Unit:=wdCharacter, count:=1
Selection.Delete Unit:=wdCharacter, count:=1
End Sub
I also use this macro to disable spell check in the textboxes
because usually they contain a bunch of C++ example code:
Sub NoSpellCheck()
Selection.Range.SpellingChecked = True
Selection.Range.NoProofing = True
End Sub

VBA works, but screen doesn't go to cursor

I have a Word macro that finds the selected text throughout the document, highlights all occurrences, and returns to the starting point (via a bookmark it sets first). The only problem is, after running it, Word displays the page above the bookmark (where the cursor is). The cursor isn't on screen at all.
After running it, I can tap a key and the screen moves to display the entry point. I added a line to do the same thing within the macro (move right one character), and it still drops me a page above. I tried using SmallScroll on the window, but that moves the insertion point. I need to end up where I started.
What can I do?
Sorry about not posting the code before, I couldn't get it to format as code. (I blame IE8 on a federal network.)
Sub AcronymHilighter()
''''''''''''''''''''''''''''''''''''''''
' Check that user has selected some text
''''''''''''''''''''''''''''''''''''''''
Dim strGetAcronym As String
If Not Selection.Type = wdSelectionNormal Then
MsgBox "Please select some text.", vbInformation
Exit Sub
End If
'''''''''''''''''''
' Set a bookmark at the current location
'''''''''''''''''''
ActiveDocument.Bookmarks.Add _
Name:="MarkReturn", Range:=Selection.Range
'''''''''''''''''''
' Save the current track changes state, then turn it off
'''''''''''''''''''
Dim bTrackingAsWas As Boolean
bTrackingAsWas = ActiveDocument.TrackRevisions
ActiveDocument.TrackRevisions = False
ActiveDocument.ShowRevisions = False
''''''''''''''''''
' Find & highlight the text
''''''''''''''''''
strGetAcronym = Selection.Text
Selection.Range.HighlightColorIndex = wdYellow
Selection.Collapse wdCollapseEnd
With Selection.Find
.Text = strGetAcronym
.Highlight = False
.Wrap = wdFindContinue
.MatchCase = True
Do While .Execute
Selection.Range.HighlightColorIndex = wdYellow
Loop
End With
'''''''''''''''''''''''''''''
' Return to the starting point,
' restore Track Changes to the previous state
'''''''''''''''''''''''''''''
Selection.GoTo what:=wdGoToBookmark, Name:="MarkReturn"
ActiveWindow.SmallScroll Down:=2
ActiveDocument.TrackRevisions = bTrackingAsWas
ActiveDocument.ShowRevisions = True
End Sub
Pardon my excessive commenting, I like to remind myself what everything does; the last time I wrote code, it was in BASIC in 1985.
I'm not fully aware of your problem (since you didn't post your code), but this bit does the work you described:
Sub MarkAndGoBack()
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="Bookmark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
Dim doc As Document
Dim para As Paragraph
Set doc = ActiveDocument
For Each aWord In doc.Words
If aWord.Text = "WantedWord" Then aWord.HighlightColorIndex = wdYellow
Next aWord
Selection.GoTo What:=wdGoToBookmark, Name:="Bookmark"
ActiveDocument.Bookmarks("Bookmark").Delete
With ActiveDocument.Bookmarks
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
End Sub
It searches for the Word "WantedWord" and highlights it yellow. After that, you will be forwarded to your initially created bookmark. It shows the correct page with cursor for me. If you want to do an Input search, you have to replace "WantedWord" with an InputBox.