I am trying to create a tool to programmatically replace the header on a large set of documents. I chose to use VBS because I am familiar with it and it needs no installed software on a user's computer.
I am using this subroutine to remove the existing header:
Sub clearHeader()
Dim oSection
For Each oSection In objDoc.Sections
For Each oFF In oSection.Headers
oFF.Range.Delete
Next
Next
End Sub
Unfortunately, this also changes the tab stops to a nonstandard dimension. (This change doesn't happen if I use the subroutine on a blank document, so it must be based on the formatting of the documents I'd like to process.)
It seems like the best option at this point is to simply set the tab stops to be where they ought to be, regardless of where they end up after the first step.
I am using the following subroutine to try and adjust the tab stops within the header, but am receiving an error that reads:
"Object doesn't support this property and method: 'thisHeader.TabStops'"
Sub moveTab()
Dim thisSection
For Each thisSection In objDoc.Sections
For Each thisHeader In thisSection.Headers
For Each aTab In thisHeader.TabStops
par.TabStops(432).Position = 468
Next
Next
Next
End Sub
I am only somewhat familiar with Object Oriented Programming, so I apologize if this is a straight forward mistake.
I've tried making macros in Word and then translating the VBA to VBS, but with little success.
That's because TabStops isn't a member of the HeaderFooter class.
It is a member of the Paragraphs class, however, which you can access through the Range property of a HeaderFooter.
For example, this will add a tab stop at 2.5" for each header/footer type (Primary, First Page, Even Pages):
Dim thisHeader ' As HeaderFooter
For Each thisHeader In thisSection.Headers
thisHeader.Range.Paragraphs.TabStops.Add objWord.InchesToPoints(2.5)
Next
Related
I use a long Excel spreadsheet containing incorrect and correct terms to check consistency between documents (e.g. anti-citrullinated is always hyphenated). I've added quite a few of these as autocorrect entries via the AutoCorrect Options feature in Word but it's time-consuming .
I came across the following code that will add long lists of autocorrects.
Sub BatchAddAutoCorrectEntries()
Dim objTable As Table
Dim objOriginalWord As Cell
Dim objOriginalWordRange As Range
Dim objReplaceWordRange As Range
Dim nRowNumber As Integer
Set objTable = ActiveDocument.Tables(1)
nRowNumber = 1
For Each objOriginalWord In objTable.Columns(1).Cells
Set objOriginalWordRange = objOriginalWord.Range
objOriginalWordRange.MoveEnd Unit:=wdCharacter, Count:=-1
Set objReplaceWordRange = objTable.Cell(nRowNumber, 2).Range
objReplaceWordRange.MoveEnd Unit:=wdCharacter, Count:=-1
AutoCorrect.Entries.Add Name:=objOriginalWordRange.Text, Value:=objReplaceWordRange.Text
nRowNumber = nRowNumber + 1
Next objOriginalWord
MsgBox ("All autocorrect items in the table1 are added.")
End Sub
It doesn't preserve any formatting: super- or subscripts, etc. Formatting autocorrect entries are stored in the Normal.dotm file and not in the regular .acl file so I haven't been able to figure out a way around this.
In a similar post, someone suggested a Find and Replace macro but Find and Replace doesn't allow me to replace with super- or subscripts.
There are two methods of adding Auto Correct Entries, Add and AddRichText. It is this second one that you use for formatted entries.
When faced with an issue like this my first resort is to check the Object Brower in the VBA editor (press F2 to display) to see what methods and properties may be available. My next step is to look them up in the VBA technical reference, aka Help, to check the usage.
If the problem is just sub/superscribt, then you could use uni-codes. Those are also available in autocorrect. Fx writing the unicodes ₁₂₃₄₅₆₇₈₉ instead of using formating on a normal 2. Most (but not all) characters exist in super and sub unicode.
The program is not working. It is giving an error message
Compile Error Expected Function or Variable
It is showing the following line as error
Autocorrect.Entries.Add Name:=objOriginalWordRange.Text, Value:=objReplaceWordRange.Text
I'm trying to insert a formatted table that I have saved in word named "DV Table" as part of the building blocks using VBA. I need this table to be inserted at the 13th paragraph of the word document.
Here's my code below. The first 3 lines just sets the selection to be at the 12th paragraph and create a new paragraph (13) after that. The last line of code is to insert the table. But when I run this, it gives the error.
Compile Error: Sub or Function not defined
I guess that this is not the proper way of defining the location. Would like some help on this. Thanks.
ActiveDocument.Paragraphs(12).Range.Select
Selection.EndKey Unit:=wdLine
Selection.Paragraphs.Add
ActiveDocument.AttachedTemplate.BuildingBlockEntries("DV Table" _
).Insert Where:=Paragraphs(13).Range.Select, RichText:=True
The Where parameter requires a Range object. There are two problems with Paragraphs(13).Range.Select
it's a method - it's an action, selecting something, not returning an object
Paragraphs(13) isn't "fully qualified" - VBA doesn't know what it is/what is meant.
One possibility would be
ActiveDocument.Paragraphs(13).Range
Notice ActiveDocument. preceding Paragraphs: this "fully qualifies" Paragraphs(13) - it tells VBA to what that belongs. And, since Where requires a Range object, Paragraphs(13).Range should be a correct "target" (I have not tested your code).
Generally, it's preferable not to work with Selection, just with Range objects. There's usually no need to actually select something using VBA. An alternative to the code snippet in the question could be
Dim rng As Word.Range
Set rng = ActiveDocument.Paragraphs(13).Range
rng.Collapse wdCollapseEnd 'like pressing right-arrow for a selection
rng.InsertParagraphAfter
rng.Collapse wdCollapseStart ' like pressing left-arrow for a selection
'rng.Select ' for testing / demo purposes
ActiveDocument.AttachedTemplate.BuildingBlockEntries("DV Table" _
).Insert Where:=rng, RichText:=True
In this case, the selection in the document does not change. There's no screen flicker; and code executes more quickly. This way of working takes getting used to, but once one is familiar with it, it's much easier to recognize what the code should be doing... Selection is rather vague as to what is being manipulated, especially if there's a lot of code using it.
I have a simple vba code in Word 2010:
Sub IncreaseIndent()
For Each p In Selection.Paragraphs
p.LeftIndent = p.LeftIndent + InchesToPoints(0.25)
p.FirstLineIndent = InchesToPoints(-0.25)
Next
End Sub
It works great, does what I need, and I have it associated to a shortcut key. But I'm trying to figure out one last glitch it has. When I use it, the paragraph indents, but it's not visually refreshed properly in the document. I have to scroll so that the text goes out of view, and then scroll it back. (Any action that makes Word re-render works, like switching to another program whose window is on top of Word, and back again.) After that, the paragraph looks as it should.
I'm thinking I'm missing some kind of p.Refresh / Re-render / Recalc command, but don't know what that is. Anyone know how to cause the refresh in the vba code?
Thanks,
Sandra
I was not able to replicate what you describe, but there is a .ScreenRefresh method which might do the trick.
https://msdn.microsoft.com/en-us/library/office/ff193095(v=office.15).aspx
Note: in the example code provided at MSDN (and as modified slightly, below), when I test it the toggling ScreenUpdating property has no effect, it always appears to update for me when I run it, even when set explicitly to False
Sub t()
Dim rngTemp As Range
Application.ScreenUpdating = False
Set rngTemp = ActiveDocument.Range(Start:=0, End:=0)
rngTemp.InsertBefore "new"
Application.ScreenRefresh
Application.ScreenUpdating = True
End Sub
I have quite a large word document (> 400 pages) with lots of cross references to headings. So far, I have always referred to the title of the heading, but now I would like to change that and refer to the page the heading resides on.
I didn't find a solution to this via the GUI (except manual treatment, of course), so I was looking into writing some VBA. Unfortunately, I have only found a way to list all targets that can be cross referenced (via GetCrossReferenceItems), but I need a way to access the actual cross reference field.
Can you help me with that? Is a cross reference field the same as a hyperlink?
Cross-references are fields in a Word document, and can be accessed via the Fields collection (ActiveDocument.Fields). You can loop through them like any other collection and check their types to see if it's one you want to work on. It looks like cross-references to text are type 3 (wdFieldRef) and cross-references to page numbers are type 37 (wdFieldPageRef). Changing fields can be a little tricky; the following should get you started:
Sub ChangeFields()
Dim objDoc As Document
Dim objFld As Field
Dim sFldStr As String
Dim i As Long, lFldStart As Long
Set objDoc = ActiveDocument
' Loop through fields in the ActiveDocument
For Each objFld In objDoc.Fields
' If the field is a cross-ref, do something to it.
If objFld.Type = wdFieldRef Then
'Make sure the code of the field is visible. You could also just toggle this manually before running the macro.
objFld.ShowCodes = True
'I hate using Selection here, but it's probably the most straightforward way to do this. Select the field, find its start, and then move the cursor over so that it sits right before the 'R' in REF.
objFld.Select
Selection.Collapse wdCollapseStart
Selection.MoveStartUntil "R"
'Type 'PAGE' to turn 'REF' into 'PAGEREF'. This turns a text reference into a page number reference.
Selection.TypeText "PAGE"
'Update the field so the change is reflected in the document.
objFld.Update
objFld.ShowCodes = True
End If
Next objFld
End Sub
Recently I started getting the error 1004: PasteSpecial method of Range class failed. I know people have said before that it might be that it is trying to paste to the active sheet when there is none, however, as you can see, everything is based on ThisWorkbook so that shouldn't be the problem. It happens extra much when Excel doesn't have the focus.
'references the Microsoft Forms Object Library
Sub SetGlobals()
Set hwb = ThisWorkbook' home workbook
Set mws = hwb.Worksheets("Code Numbers") ' main worksheet
Set hws = hwb.Worksheets("Sheet3") ' home worksheet (Scratch pad)
Set sws = hwb.Worksheets("Status") ' Status sheet
Set aws = hwb.Worksheets("Addresses") ' Addresses sheet
End Sub
Sub Import()
Call SetGlobals
hws.Select
'a bunch of code to do other stuff here.
For Each itm In itms
Set mitm = itm
body = Replace(mitm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
Call Buf.SetText(body)
Call Buf.PutInClipboard
Call hws.Cells(k, 1).Select
Call hws.Cells(k, 1).PasteSpecial
For Each shape In hws.Shapes
shape.Delete
Next shape
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub
Update: mitm and itm have two different types, so I did it for intellisense and who knows what else. This code takes a list of emails and pastes them into excel so that excel parses the html (which contains tables) and pastes it directly into excel. Thus the data goes directly into the sheet and I can sort it and parse it and whatever else I want.
I guess I'm basically asking for anyone who knows another way to do this besides putting it in an html file to post it. Thanks
This probably will not exactly answer your problem - but I noticed a few things in your source code that are too long to place in a comment, so here it is. Some of it is certainly because you omitted it for the example, but I'll mention it anyway, just in case:
Use Option Explicit - this will avoid a lot of errors as it forces you to declare every variable
Call SetGlobals can be simplified to SetGlobals - same for Call Buf.SetText(body) = Bof.SetText Body, etc.
No need to '.Select' anything - your accessing everything directly through the worksheet/range/shape objects (which is best practice), so don't select (hws.Select, hws.Cells(k,1).Select)
Why Set mitm = itm? mitm will therefore be the same object as itm - so you can simply use itm
You're deleteing all shapes in hwsmultiple times - for each element in itms. However, once is enough, so move the delete loop outside of the For Each loop
Instead of putting something in the clipboard and then pasting it to a cell, just assign it directly: hws.Cells(k, 1).Value = body - this should solve your error!
Instead of using global variables for worksheets that you assign in 'SetGlobals', simply use the sheet objects provided by Excel natively: If you look at the right window in the VBE with the project tree, you see worksheet nodes Sheet1 (sheetname), Sheet2 (sheetname), etc.. You can rename these objects - go to their properties (F4) and change it to meaningful names - or your current names (hwb, mws, ...) if you want. Then you can access them throughout your code without any assignment! And it'll work later, even if you change the name of Sheet3to something meaningful! ;-)
Thus, taking it all into account, I end up with the following code, doing the same thing:
Option Explicit
Sub Import()
'a bunch of code to do other stuff here.
For Each shape In hws.Shapes
shape.Delete
Next shape
For Each itm In itms
Call hws.Cells(k, 1) = Replace(itm.HTMLBody, "<img border=""0"" src=""http://www.simplevoicecenter.com/images/svc_st_logo.jpg"">", "")
'Some code to set the value of k
'and do a bunch of other stuff.
Next itm
End Sub