VBA Word; How to resize bookmark label range? - vba

I have messed cross-references to pictures in my word document. The label shows only part of the figure name:
Figure 5-
I have found out that bookmark responsible for that has narrowed range than the full figure name:
[Figure 5-] 62: Caption text
I would like to extend the bookmark label up to ":" using VBA, but I have no idea how to go further with the code.
Bookmark.Start and Bookmark.End refer to the whole picture text so how to refer only to label? my code is as follow:
Sub extend_bookmarks()
Dim bmk As Bookmark
Dim msg As String
Dim pos As Integer
For Each bmk In ActiveDocument.Range.Bookmarks
If (InStr(1, bmk.Range.Text, "Figure") And IsNumeric(Mid(bmk.Range.Text, 8, 1))) Then
pos = InStr(1, bmk.Range.Text, ":")
If ((pos < 12) And (pos > 0)) Then
Debug.Print bmk.Name
Debug.Print bmk.Range.Text
Debug.Print bmk.End - bmk.Start; pos
End If
End If
Next bmk
End Sub

You could just reapply the bookmark using the paragraph it sits in as the range.
Sub extend_bookmarks()
Dim bmk As Variant
For Each bmk In ActiveDocument.Range.Bookmarks
ActiveDocument.Bookmarks.Add Range:=bmk.range.Paragraphs(1).range, Name := bmk.Name
Next
End Sub
Update, When I tested the code above I only stepped through the loop twice and so missed the obvious, that you cannot use 'for each' when you are changing the content of a collection.
The code below correctly extends the bookmarks as intended and does not crash word.
Sub extend_bookmarks()
Dim myCount As Long
myCount = ActiveDocument.Bookmarks.Count
Dim myIndex As Long
With ActiveDocument.Bookmarks
For myIndex = myCount To 1 Step -1
.Add Range:=.Item(myIndex).Range.Paragraphs(1).Range, Name:=.Item(myIndex).Name
Next
End With
End Sub

Related

Sub to find text in a Word document by specified font and font size

Goal: Find headings in a document by their font and font size and put them into a spreadsheet.
All headings in my doc are formatted as Ariel, size 16. I want to do a find of the Word doc, select the matching range of text to the end of the line, then assign it to a variable so I can put it in a spreadsheet. I can do an advanced find and search for the font/size successfully, but can't get it to select the range of text or assign it to a variable.
Tried modifying the below from http://www.vbaexpress.com/forum/showthread.php?55726-find-replace-fonts-macro but couldn't figure out how to select and assign the found text to a variable. If I can get it assigned to the variable then I can take care of the rest to get it into a spreadsheet.
'A basic Word macro coded by Greg Maxey
Sub FindFont
Dim strHeading as string
Dim oChr As Range
For Each oChr In ActiveDocument.Range.Characters
If oChr.Font.Name = "Ariel" And oChr.Font.Size = "16" Then
strHeading = .selected
Next
lbl_Exit:
Exit Sub
End Sub
To get the current code working, you just need to amend strHeading = .selected to something like strHeading = strHeading & oChr & vbNewLine. You'll also need to add an End If statement after that line and probably amend "Ariel" to "Arial".
I think a better way to do this would be to use Word's Find method. Depending on how you are going to be inserting the data into the spreadsheet, you may also prefer to put each header that you find in a collection instead of a string, although you could easily delimit the string and then split it before transferring the data into the spreadsheet.
Just to give you some more ideas, I've put some sample code below.
Sub Demo()
Dim Find As Find
Dim Result As Collection
Set Find = ActiveDocument.Range.Find
With Find
.Font.Name = "Arial"
.Font.Size = 16
End With
Set Result = Execute(Find)
If Result.Count = 0 Then
MsgBox "No match found"
Exit Sub
Else
TransferToExcel Result
End If
End Sub
Function Execute(Find As Find) As Collection
Set Execute = New Collection
Do While Find.Execute
Execute.Add Find.Parent.Text
Loop
End Function
Sub TransferToExcel(Data As Collection)
Dim i As Long
With CreateObject("Excel.Application")
With .Workbooks.Add
With .Sheets(1)
For i = 1 To Data.Count
.Cells(i, 1) = Data(i)
Next
End With
End With
.Visible = True
End With
End Sub

How to determine in VBA the Heading-X styled heading just above the selection?

I have a document with multi-level headings -- table of contents, styles Heading 1-n, all that. When I pull up the Navigation Pane and move the text cursor within the document, the Navigation Pane highlights the heading closest to the cursor position. Isn't there some way get what that heading is in VBA -- some property of the Range or Selection object?
In a class module that has a Word-Application object WithEvents I've written a WindowSelectionChange event handler to search for "^p" with styled Heading 1 or Heading 2, determine which one is closer, get that heading's text and then do stuff with it. It should be simpler and faster to get the nearest heading's text.
Private Sub appWord_WindowSelectionChange(ByVal Sel As Word.Selection)
Dim lHdrPosn As Long, HP As Long
Dim sStyle As String
Dim rngSelPosn As Word.Range
Dim sHdrText As String
Dim lRTFposn As Long, lRTFselLength As Long
With Sel
If Not (.Document Is ThisDocument) Then Exit Sub
Set rngSelPosn = .Range
rngSelPosn.Collapse IIf(.StartIsActive, wdCollapseStart, wdCollapseEnd)
End With
With rngSelPosn
lHdrPosn = -1
For HP = 2 To 1 Step -1
sStyle = "Heading " & HP
With .Find ' Find a paragraph mark of style Heading (HP)
.ClearFormatting
.Style = sStyle
.Forward = (Sel.Style = sStyle) ' This is case user clicks in a heading
' Get the later one
If .Execute("^p") Then If lHdrPosn = -1 Or rngSelPosn.Start > lHdrPosn Then lHdrPosn = rngSelPosn.Start
End With
Next
If lHdrPosn < 0 Then Exit Sub
End With
sHdrText = ThisDocument.Characters(lHdrPosn).Paragraphs(1).Range.Text
With frmHelpWindow.rtfHelpText ' Here's the header's text
lRTFposn = .Find(vbCrLf & sHdrText & vbLf, 0, Len(.TextRTF))
If lRTFposn < 0 Then Exit Sub
lRTFselLength = .SelLength
.SelStart = Len(.TextRTF)
.SelStart = lRTFposn + 2
.SelLength = lRTFselLength - 2
.Refresh
End With
End Sub
There's an old WordBasic bookmark that can be used for this. It requires Selection, so the cursor position is fine:
Selection.Bookmarks("\HeadingLevel").Range
To get the closest, previous heading paragraph, no matter which level:
Selection.Bookmarks("\HeadingLevel").Range.Paragraphs(1)
To get the text of the heading (for example):
Selection.Bookmarks("\HeadingLevel").Range.Paragraphs(1).Range.Text

How to mark and recognize back a table via bookmarks

I am trying to insert tables marked with a Name via a bookmark so I can later recognize them again.
Below I have added my source code in question. At pos3 I created a table with 2 rows and add a bookmark for its range. But when repeating the Sub I always end up in the case of pos1 .. my bookmark is not found in the table selection. (trying to reach pos2)
The bookmark itself is added, but maybe not to the table. I suspect the error to be there.
I can see the bookmark in the bookmark-list of Word. But if I do a manual "go to" the cursor seems to end up off screen somewhere, so I suspect its not added correctly to the table range.
Private Sub PrepareFooter()
Dim oSection As Section
Dim oFooter As HeaderFooter
Dim oRng As Range
Dim tbl As Table
Dim cell As cell
Dim foundFooterTable As Boolean
For Each oSection In ActiveDocument.Sections
For Each oFooter In oSection.Footers
With oFooter.Range
For Each tbl In .Tables
tbl.Select
If Selection.Bookmarks.Count <> 1 Then
tbl.Delete ' <-- pos1
ElseIf Selection.Bookmarks(1).Name <> "FooterTable" Then
tbl.Delete
Else
foundFooterTable = True ' <-- pos2
FormatFooterTable tbl
End If
Next
End With
oFooter.Range.Select
Selection.Collapse wdCollapseStart
If Not foundFooterTable Then
Set tbl = ActiveDocument.Tables.Add(Selection.Range, 2, 1)
tbl.Select
ActiveDocument.Bookmarks.Add Range:=Selection.Range
, Name:="FooterTable" ' <- pos3
FormatFooterTable tbl
End If
Next oFooter
Next oSection
End Sub
thanks for any ideas about what I might do wrong!
Try to work without Selection as much as you can. Whenever possible, use a Range object. That will make your code clearer and more reliable.
In order to put a bookmark "around" a table (pos 3):
ActiveDocument.Bookmarks.Add Range:=tbl.Range, Name:="FooterTable"
When this works, you should be able to get the table using:
Dim sFooterTable as String
sFooterTable = "FooterTable"
If ActiveDocument.Bookmarks.Exists(sFooterTable) Then
Set tbl = ActiveDocument.Bookmarks(sFooterTable).Range.Tables(1)
found my mistake:
I was applying the same bookmark name on all tables that were found .. this way deleting the previous bookmarks as they need a unique name.
adding a unique identifier in the end (I used an integer now) made the code work.

Word: insert an Autotext shape, then move it

I'm trying to insert an autotext item into a header, and then move the autotext item only if it is on an even page that's also the first page in a section.
My code will insert the autotext, but I can't figure out how to move it.
Sub InsertHeader()
Dim oShape As Shape
Dim PageNumber As Integer
Dim oSection As Section
Dim oHeader As HeaderFooter
For Each oSection In ActiveDocument.Sections
If oSection.Index > 1 Then
For Each oHeader In oSection.Headers
oHeader.Range.Select
PageNumber = Selection.Information(wdActiveEndPageNumber)
If oHeader.Exists Then
Select Case oHeader.Index
Case Is = wdHeaderFooterFirstPage
If PageNumber Mod 2 = 0 Then
ActiveDocument.AttachedTemplate.AutoTextEntries("HeaderFirst"). _
Insert Where:=Selection.Range
End If
End Select
End If
Next oHeader
End If
Next oSection
End Sub
I tried putting Insert Where:=Selection.Range Left:=CentimetersToPoints(2.26) but the VBA editor won't accept that. I also tried finding all shapes in the header and moving them:
ActiveDocument.AttachedTemplate.AutoTextEntries("HeaderFirst"). _
Insert Where:=Selection.Range
For Each oShape In oHeader.Shapes
oShape.Left = CentimetersToPoints(2.26)
''oHeader.Range.Shape(1).Left = CentimetersToPoints(1)
Next oShape
But that moves the shapes in every header in the document, not just the shape I inserted.
Found it!
After inserting the header, I have to select it, then move the selection:
oHeader.Range.Select
Selection.Range.ShapeRange.Left = CentimetersToPoints(2.26)
Also, I needed to make sure the header existed before inserting anything. I solved that by having the program that generates the Word file (Author-it) insert a temporary header.

How do you remove hyperlinks from a Microsoft Word document?

I'm writing a VB Macro to do some processing of documents for my work.
The lines of text are searched and the bracketed text is put in a list(box).
The problem comes when I want to remove all hyperlinks in the document and then generate new ones (not necessarily in the location of the original hyperlinks)
So the problem is How do I remove the existing hyperlinks?
My current issue is that every time a link gets added, the hyperlinks count goes up one, but when you delete it, the count does NOT reduce. (as a result I now have a document with 32 links - all empty except for 3 I put in myself - they do not show up in the document)
At the end of the code are my attempts at removing the hyperlinks.
Private Sub FindLinksV3_Click()
ListOfLinks.Clear
ListOfLinks.AddItem Now
ListOfLinks.AddItem ("Test String 1")
ListOfLinks.AddItem ActiveDocument.FullName
SentenceCount = ActiveDocument.Sentences.Count
ListOfLinks.AddItem ("Sentence Count:" & SentenceCount)
counter = 0
For Each myobject In ActiveDocument.Sentences ' Iterate through each element.
ListOfLinks.AddItem myobject
counter = counter + 1
BracketStart = (InStr(1, myobject, "("))
If BracketStart > 0 Then
BracketStop = (InStr(1, myobject, ")"))
If BracketStop > 0 Then
ListOfLinks.AddItem Mid$(myobject, BracketStart + 1, BracketStop - BracketStart - 1)
ActiveDocument.Sentences(counter).Select
ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:= _
"http://testnolink/" & counter, ScreenTip:="" 'TextToDisplay:=""
End If
End If
Next
'ActiveDocument.Sentences(1).Select
'
'Selection.Range.Hyperlinks(1).Delete
ActiveDocument.Hyperlinks.Item(1).Delete
Debug.Print ActiveDocument.Hyperlinks.Count
End Sub
This is an old post, so am adding this VBA code in case it is useful to someone.
Hyperlinks (Collections) need to be deleted in reverse order:
Sub RemoveHyperlinksInDoc()
' You need to delete collection members starting from the end going backwards
With ActiveDocument
For i = .Hyperlinks.Count To 1 Step -1
.Hyperlinks(i).Delete
Next
End With
End Sub
Sub RemoveHyperlinksInRange()
' You need to delete collection members starting from the end going backwards
With Selection.Range
For i = .Hyperlinks.Count To 1 Step -1
.Hyperlinks(i).Delete
Next
End With
End Sub
The line removing the hyperlink is commented out. The following line will remove the first hyperlink within the selected range:
Selection.Range.Hyperlinks(1).Delete
This will also decrement Selection.Range.Hyperlinks.Count by 1.
To see how the count of links is changing you can run the following method on a document:
Sub AddAndRemoveHyperlink()
Dim oRange As Range
Set oRange = ActiveDocument.Range
oRange.Collapse wdCollapseStart
oRange.MoveEnd wdCharacter
Debug.Print ActiveDocument.Range.Hyperlinks.Count
ActiveDocument.Hyperlinks.Add oRange, "http://www.example.com"
Debug.Print ActiveDocument.Range.Hyperlinks.Count
ActiveDocument.Hyperlinks.Item(1).Delete
Debug.Print ActiveDocument.Range.Hyperlinks.Count
End Sub