|
|
|
|
|
|
Many people access the material from this web site daily. Most just take what they want and run. That's OK, provided they are not selling on the material as their own; however if your productivity gains from the material you have used, a donation from the money you have saved, however small, would help to ensure the continued availability of this resource.
Click the
appropriate button above
to access PayPal. |
|
Some Useful
Macro Examples |
|
|
|
|
Frequently the Word forums throw up some interesting
exercises in macro programming. Some of the better examples that my
fellow MVPs and I have come up with appear elsewhere in the Word pages
on this site. This page offers a place to present some code examples
that may have wider use, which you can adapt to your own requirements. I
will add to the examples as they come up, but for the moment we will
start with the InsertField dialog: |
|
Insert Field formatting
switch |
|


|
|
|
The
InsertField dialog (the illustrations are from Word
2003 (top) and 2007, other Word versions are similar) has the Preserve formatting
during updates check box checked by default, with no obvious way of
resetting that default. This adds a
MERGEFORMAT switch to the
inserted field. Frankly I have never found any real use for the switch
and so I always uncheck it .... when of course I remember, so the first
macro I created simply intercepts the InsertFile command and uses the
SendKeys command to physically uncheck the box i.e. |
|
|
Sub
InsertField()
SendKeys "{Tab}{Tab} +{Tab}+{Tab}"
Dialogs(wdDialogInsertField).Show
End Sub |
|
|
This worked fine, until fellow MVP Paul Edstein, who uses the
pseudonym Macropod in the forums, baited me to produce a version which gave the user
the opportunity to add a
CHARFORMAT switch as an alternative to the
MERGEFORMAT switch. The
result was the following.
Inserting a field from the Insert > Field menu
option (Insert > Quick Parts > Field in Word 2007/2010) opens the dialog with the check box
unchecked, using the same method as above, but if you check the box, you
are presented with a message box which offers the opportunity to choose
the type of formatting switch, then adds the appropriate switch to the
field.
Check the
box and you will see the further dialog |
|

|
|
|
The result
is that the field may be inserted with either switch as appropriate e.g.
{
CREATEDATE \@ "dddd, dd MMMM yyyy" \* CHARFORMAT }
by selecting YES
{
CREATEDATE \@ "dddd, dd MMMM yyyy" \* MERGEFORMAT }
by selecting No
or none if the Insert Field Dialog box
is left unchecked. {
CREATEDATE \@ "dddd, dd MMMM yyyy" } |
|
|
Sub
InsertField()
Dim oRng As
Range
Dim i As Variant
Dim sSwitch As String
Dim strChoice As
String
SendKeys "{Tab}{Tab} +{Tab}+{Tab}"
Dialogs(wdDialogInsertField).Show
On Error Goto
Finish 'User has cancelled
Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
Set oRng = Selection.Range
For i = 1 To
oRng.Fields.Count
With
oRng.Fields(i)
If InStr(1, .Code, "MERGEFORMAT") <> 0
Then
sSwitch = MsgBox("Use charformat in place of the mergeformat
switch?", _
vbYesNo, _
"Insert Field")
If sSwitch = vbYes Then
.Code.Text = Replace(.Code.Text, _
"MERGEFORMAT", _
"CHARFORMAT")
End If
End
If
.Update
End
With
Next i
Selection.MoveRight Unit:=wdCharacter, Count:=1
Finish:
End Sub |
|
Note: |
I am
informed, by the aforementioned Paul Edstein, that the SendKeys approach will not work under the Windows Vista operating
system, returning error code 70: "Permission denied"
- so that's another
reason why I will be keeping Windows XP for the foreseeable future.
This then negates the use of the above macro for Vista users,
but I have included a modified version below with the SendKeys line
removed and a separate step to remove the switch. It is not as elegant
as un-checking the check box, but it does the job. |
|
Windows Vista
Version |
| Note: |
The
following will work in Windows XP also, but requires an extra step to
overcome the SendKeys issue. |
| |
Sub
InsertField()
Dim oRng As
Range
Dim i As Variant
Dim sSwitch As String
Dim strChoice As
String
Dialogs(wdDialogInsertField).Show
On Error Goto
Finish 'User has cancelled
Selection.MoveLeft Unit:=wdCharacter, Count:=1, Extend:=wdExtend
Set oRng = Selection.Range
For i = 1 To
oRng.Fields.Count
With
oRng.Fields(i)
If InStr(1, .Code, "MERGEFORMAT") <> 0
Then
sSwitch = MsgBox("Use charformat in place of the
mergeformat
switch?", _
vbYesNo, _
"Insert Field")
If sSwitch = vbYes Then
.Code.Text = Replace(.Code.Text, _
"MERGEFORMAT", _
"CHARFORMAT")
End If
If sSwitch = vbNo
Then
sSwitch = MsgBox("Remove switch?", _
vbYesNo, _
"Insert Field")
If sSwitch = vbYes Then
.Code.Text = Replace(.Code.Text, _
" \* MERGEFORMAT ", _
"")
End If
End If
End
If
.Update
End
With
Next i
Selection.MoveRight Unit:=wdCharacter, Count:=1
Finish:
End Sub |
|
|
The Vista
version of the macro has two message boxes. One of
them is identical to the Windows XP version, the other is displayed when
the user responds to the first box with 'No' |
|


|
|
Number
documents |
|
|
There is a
page on this site dedicated to numbering documents but on a
number of occasions I have been asked for a variation of this to place
an incrementing number at a bookmarked location in a series of
documents. The example used here was created to print a batch of
numbered receipts, and includes a second macro to reset the stored start
number.
The macro uses a bookmark in the document template named
RecNo |
|
|
Sub
AddNoFromINIFileToBookmark()
Dim SettingsFile As
String
Dim Order As String
Dim iCount As String
Dim rRecNo As
Range
Dim i As
Long
iCount = InputBox("Print how many copies?", _
"Print Numbered Copies", 1)
If iCount = "" Then
Exit Sub
SettingsFile =
Options.DefaultFilePath(wdStartupPath) & "\Settings.ini"
Order = System.PrivateProfileString(SettingsFile, _
"DocNumber", "Order")
If Order = "" Then
Order = 1
End If
For i = 1 To
iCount
Set
rRecNo = ActiveDocument.Bookmarks("RecNo").Range
rRecNo.Text = Format(Order,
"00000")
With
ActiveDocument
.Bookmarks.Add
"RecNo", rRecNo
.Fields.Update
.ActiveWindow.View.ShowFieldCodes
= False
.PrintOut
End
With
Order = Order + 1
Next i
System.PrivateProfileString(SettingsFile, "DocNumber",
_
"Order") = Order
End Sub
Sub ResetStartNo()
Dim SettingsFile As
String
Dim Order As String
Dim sQuery As String
SettingsFile = Options.DefaultFilePath(wdStartupPath) & "\Settings.ini"
Order = System.PrivateProfileString(SettingsFile, _
"DocNumber", "Order")
sQuery = InputBox("Reset start number?", "Reset", Order)
If sQuery = "" Then
Exit Sub
Order = sQuery
System.PrivateProfileString(SettingsFile, "DocNumber",
_
"Order") = Order
End Sub
|
|
|
Instead of printing a batch of similar numbered
documents, the following variation simply adds the incremented number to
each new document created from the template at the bookmarked location
named RecNo. The reset macro above will reset this version
equally as the following uses the same stored number data. |
|
|
Sub
AutoNew()
Dim SettingsFile
As String
Dim Order
As String
Dim rRecNo
As Range
Dim i
As Long
SettingsFile = Options.DefaultFilePath(wdStartupPath) & "\Settings.ini"
Order = System.PrivateProfileString(SettingsFile, _
"DocNumber", "Order")
If Order = ""
Then
Order = 1
End If
Set rRecNo =
ActiveDocument.Bookmarks("RecNo").Range
rRecNo.Text = Format(Order, "00000")
With
ActiveDocument
.Bookmarks.Add "RecNo", rRecNo
.Fields.Update
.ActiveWindow.View.ShowFieldCodes =
False
End With
Order = Order + 1
System.PrivateProfileString(SettingsFile, "DocNumber", _
"Order") = Order
End Sub |
|
Paste
unformatted text |
|
|
If you
paste text from the internet for example, the paste will bring across
all the formatting of the web page, whereas users frequently require the
pasted text to adopt the formatting of the document into which it is
pasted. This can be achieved with Paste Special > Unformatted text, but
the macro recorder will not accurately record that action so.... |
|
|
Sub
PasteUnfText()
On Error GoTo
oops
Selection.PasteSpecial _
DataType:=wdPasteText, _
Placement:=wdInLine
End
oops:
Beep
End Sub |
|
Copy
footnotes c/w formatting to a new document |
|
|
Sub
CopyFootnotes()
Dim sDoc
As Document
Dim tDoc
As Document
Dim sId
As String
Set sDoc =
ActiveDocument
Set tDoc =
Documents.Add
For i = 1
To sDoc.Footnotes.Count
sId = sDoc.Footnotes(i).Index
sDoc.Footnotes(i).Range.Select
Selection.Copy
tDoc.Activate
With Selection
.Style = "Footnote Text"
.Font.Superscript = True
.TypeText sId & " "
.Font.Superscript = False
.Paste
.TypeParagraph
End With
sDoc.Activate
Next i
tDoc.Activate
End Sub
|
|
Send the
current document from Word by e-mail as an attachment, with the header
details pre-completed, e.g. for the return of a completed form document. |
|
|
Sub
SendDocumentAsAttachment()
'This
macro requires the Outlook Object library to be checked
'in
the vba editor Tools > References
Dim bStarted As Boolean
Dim oOutlookApp As
Outlook.Application
Dim oItem As
Outlook.MailItem
On Error Resume Next
If Len(ActiveDocument.Path) = 0
Then 'Document has
not been saved
ActiveDocument.Save
'so save it
End If
'see if Outlook is running and if so turn your
attention there
Set oOutlookApp = GetObject(, "Outlook.Application")
If Err <> 0 Then
'Outlook isn't running
'So fire it up
Set oOutlookApp = CreateObject("Outlook.Application")
bStarted =
True
End If
'Open a new e-mail message
Set oItem =
oOutlookApp.CreateItem(olMailItem)
With oItem 'and add
the detail to it
.To = "someone@somewhere.com"
'send to this address
.Subject = "New
subject" 'This is the message subject
.Body = "See attached
document" ' This is the message body text
.Attachments.Add
Source:=ActiveDocument.FullName, Type:=olByValue
.Send
'**********************************
'If you want to view
the message before it goes
'change the line
above from .Send to .Display
'Otherwise the
message is sent straight to the Outbox
'and if you have
Outlook set to send mail immediately,
'it will simply be
Sent
'with no obvious sign
that Outlook has operated.
'Apart from the copy
in the Outlook Sent folder
'**********************************
End With
If bStarted Then
'If the macro started Outlook, stop it again.
oOutlookApp.Quit
End If
'Clean up
Set oItem = Nothing
Set oOutlookApp =
Nothing
End Sub |
|
Toggle the SQL security entry in the registry through vba |
|
|
You receive the "Opening this will run the following SQL
command" message when you open a Word mail merge main document that is
linked to a data source -
http://support.microsoft.com/?kbid=825765
This linked page explains how to create registry entries
to turn off the security message. Some users have been concerned about
the security implications of turning off this warning message. The
following code was conceived with that issue in mind. The macro creates
the registry entry if it is not present and then toggles the setting
between 0 and 1 each time the macro is run. It could therefore be
adapted for use in a mail merge macro to switch off the warning while
the particular merge was run, then switch it back on again on
completion. |
|
|
Sub
ToggleSQLSecurity()
Dim WSHShell, RegKey, rKeyWord, wVer
Set WSHShell = CreateObject("WScript.Shell")
wVer = Application.Version
If wVer < 10 Then
'The security issue relates to
'Word versions
greater than 10.0 (Word 2002)
MsgBox "This macro is
for Word 2002 and later!", vbOKOnly, "Wrong Word Version"
Exit Sub
End If
Start:
RegKey = "HKEY_CURRENT_USER\Software\Microsoft\Office\" & wVer &
"\Word\Options\"
On Error Resume Next
'The registry key does not exist
rKeyWord = WSHShell.RegRead(RegKey & "SQLSecurityCheck")
If rKeyWord = "" Then
WSHShell.regwrite
RegKey & "SQLSecurityCheck", 1, "REG_DWORD" 'set
it at zero
GoTo Start:
'and read it again
End If
If rKeyWord = 1 Then
WSHShell.regwrite
RegKey & "SQLSecurityCheck", 0, "REG_DWORD"
MsgBox "SQL Security checking is switched off", vbInformation, "SQL
Check"
Else
WSHShell.regwrite
RegKey & "SQLSecurityCheck", 1, "REG_DWORD"
MsgBox "SQL Security checking is switched on", vbInformation, "SQL
Check"
End If
End Sub
|
|
True title
case |
|
|
Word has
the ability to set a block of text in title case, i.e. each of the words
formatted so that its first letter is capitalized, thus:
A Tale
Of Two Cities but
formatting styles often dictate that articles, prepositions, and
conjunctions should be in lower case, thus:
A Tale of Two Cities.
Word has no built-in function to perform this type of
formatting, but it can be achieved with a macro. The following sets the
selected text in Word's title case and then sets all the words in the
first array:
vFindText = Array("A", "An", "And",
"As", "At", "But", "By", "For", _
"If", "In", "Of", "On", "Or", "The", "To", "With")
to their lower case equivalents with a
corresponding array
vReplText = Array("a", "an",
"and", "as", "at", "but", "by", "for", _
"if", "in", "of", "on", "or", "the", "to", "with")
The list of corrections can be
expanded as required by simply adding the word in its alternative forms
to both lists.
If one of the listed words was the
first word in the selected text, then it too would be set in lower case,
so that too needs to be corrected, and similarly if there is a colon in
the selected text, the word following the colon would need to be
corrected. The macro forces capitalization on the first letters of
all words that appear in either position. |
| |
Sub
TrueTitleCase()
Dim sText As
Range
Dim vFindText As
Variant
Dim vReplText As
Variant
Dim i As
Long
Dim k As
Long
Dim m As Long
Set sText = Selection.Range
'count the characters in the selected string
k = Len(sText)
If k < 1 Then
'If none, then no string is selected
'so warn the user
MsgBox "Select the
text first!", vbOKOnly, "No text selected"
Exit Sub 'and quit the macro
End If
'format the selected string as title case
sText.Case = wdTitleWord
'list the exceptions to look for in an array
vFindText = Array("A", "An", "And", "As", "At", "But", "By", "For", _
"If", "In", "Of", "On", "Or", "The", "To", "With")
'list their replacements in a matching array
vReplText = Array("a", "an", "and", "as", "at", "but", "by", "for", _
"if", "in", "of", "on", "or", "the", "to", "with")
With sText
With .Find
'replace items in the first list
'with the
corresponding items from the second
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindStop
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Format = True
.MatchCase = True
For i = LBound(vFindText)
To UBound(vFindText)
.Text = vFindText(i)
.Replacement.Text = vReplText(i)
.Execute Replace:=wdReplaceAll
Next i
End With
'Reduce the range of the selected text
'to encompass only
the first character
.MoveEnd Unit:=wdCharacter,
Count:=-Len(sText) + 1
'format that character as upper case
.Case = wdUpperCase
'restore the selected text to its original length
.MoveEnd Unit:=wdCharacter,
Count:=k
'and check to see if the string contains a colon
If InStr(1, sText, ":") > 0 Then
'If it does note the position of the character
'after the first
colon
m = InStr(1, sText, ":") + 1
'and set that as the new start of the selected text
.MoveStart wdCharacter, m
'set the end of the selected text to include
'one extra character
.MoveEnd Unit:=wdCharacter, Count:=-Len(sText) + 1
'format that character as upper case
.Case = wdUpperCase
End If
End With
End Sub |
|
Extract
Acronyms to a new document |
|
|
A newsgroup
contributor asked if it was possible to extract acronyms to a new
document. The following will extract all words in the
format NATO or N.A.T.O. consisting of more than two
characters to a new document. The list is then sorted and duplicate
entries removed. The macro does not extract acronyms that are adopted as
proper nouns e.g. Unesco. |
| |
Sub
ExtractAcronyms()
Dim
rText As
Range
Dim
SDoc As
Document
Dim
TDoc As
Document
Set
SDoc = ActiveDocument
Set
TDoc = Documents.Add
SDoc.Activate
With
Selection
.HomeKey
wdStory
With
.Find
.ClearFormatting
.Replacement.ClearFormatting
.Replacement.Text = ""
Do While
.Execute(findText:="[A-Z.]{2,}", _
MatchWildcards:=True,
_
Wrap:=wdFindStop, Forward:=True)
= True
Set
rText = Selection.Range
TDoc.Range.InsertAfter
rText & vbCr
rText.Collapse wdCollapseEnd
Loop
End
With
End With
With
TDoc
.Range.Sort ExcludeHeader:=False, _
FieldNumber:="Paragraphs", _
SortFieldType:=wdSortFieldAlphanumeric, _
SortOrder:=wdSortOrderAscending
.Paragraphs(1).Range.Delete
.Activate
End With
End Sub |
|
Format part of a found text string |
|
|
Word's replace function is capable of applying formatting
to found strings, but only the whole of a found string. Sometimes it is
desirable to format only part of the string e.g. you may search for the
chemical symbol for water H2O in order to format the 2 as subscript. The
replace function cannot do that. With this example the simplest solution
is to copy the correctly formatted version to the clipboard and replace
the find string H2O with the clipboard contents H2O
i.e. put ^c in the replace with box.
OR
You could create a macro to do so. The
following shows two techniques for selecting a digit from a found item. |
|
|
Sub
Subscript2_in_H2O()
Dim
rText
As
Range
With
Selection
.HomeKey
wdStory
With
.Find
.ClearFormatting
.Replacement.ClearFormatting
Do
While
.Execute(findText:="H2O", _
MatchWildcards:=False,
_
Wrap:=wdFindStop,
_
Forward:=True)
= True
Set
rText = Selection.Range
'The found text
With
rText
'Do what you want with
the found text
'move the start position
of the found text one character right
.MoveStart Unit:=wdCharacter, Count:=1
'move the end position
of the found text one character to the left
.MoveEnd Unit:=wdCharacter, Count:=-1
'the text string is now
one character long i.e. the "2"
.Font.Subscript =
True
'apply
subscript to the remaining text string
End
With
Loop
'and
look for the next match
End With
End With
End Sub
or even simpler
Sub
Subscript2_in_H2ORev1()
With
Selection
.HomeKey wdStory
With
.Find
.ClearFormatting
.Replacement.ClearFormatting
Do While
.Execute(findText:="H2O", _
MatchWildcards:=False,
_
Wrap:=wdFindStop,
_
Forward:=True)
= True
'Do what you want with
the found text (Selection.Range)
'In this case format the second character as subscripted
Selection.Range.Characters(2).Font.Subscript =
True
Loop
'and look for
the next match
End With
End With
End Sub
|
|
Format part of a found text string
in a list of items |
|
|
Extending the above procedure, you
may wish to format a number of similar items - eg chemical formulae.
The following version defines the list of items as variants. Note that
the subscripted numbers are located in different parts of the text
string. The macro loops through the list searching for each variant
throughout the document in turn. It then uses Case statements to process
the range for each variant to achieve the results shown in red (when
pasted to the vba editor the red colour will change to green and the
format of the red coloured items will be lost).
In the cases where there are two or digits to format,
they are processed separately. You could adapt this technique to format
any character in the search strings in any manner you require. |
| |
Sub
FormatChemicalFormulae()
Dim
rText As
Range
Dim
vFindText(4)
As Variant
'match
the number in the brackets
'to the last number in
the list below
Dim
i
As Long
vFindText(0) = "H2O"
vFindText(1) = "CO2"
vFindText(2) = "H2SO4"
vFindText(3) = "SO42-"
vFindText(4) = "[CO(NH3)6]3+"
'add more numbers as
required
'increment the number
'n' in the brackets vFindText(n)
For
i = 0 To UBound(vFindText)
With
Selection
.HomeKey wdStory
With
.Find
.ClearFormatting
.Replacement.ClearFormatting
Do While
.Execute(findText:=vFindText(i), _
MatchWildcards:=False,
_
Wrap:=wdFindStop, Forward:=True)
= True
Set
rText = Selection.Range
'The found text
With
rText 'Do what
you want with the found text
Select Case
i
Case Is
= 0
'H2O
-
H2O
.Characters(2).Font.Subscript =
True
Case Is
= 1
'CO2
-
CO2
.Characters(3).Font.Subscript =
True
Case Is
= 2
'H2SO4
-
H2SO4
.Characters(2).Font.Subscript =
True
.Characters(5).Font.Subscript =
True
Case Is
= 3
'SO42-
-
SO42-
.Characters(3).Font.Subscript =
True
.Characters(4).Font.Superscript
=
True
.Characters(5).Font.Superscript =
True
Case Is
= 4
'[CO(NH3)6]3+
-
[Co(NH3)6]3+
.Characters(3).Case = wdLowerCase
.Characters(7).Font.Subscript =
True
.Characters(9).Font.Subscript =
True
.Characters(11).Font.Superscript =
True
.Characters(12).Font.Superscript =
True
End Select
End
With
Loop
'and look for
the next match
End With
End With
Next
i
End Sub
|
|
Add a row to a
table in a protected form |
| |
In
a recent Word forum question, a user wanted to automatically provide the
function to add a row to a table in a protected form and to fill the new
row with form fields to match those in the previous row, but with new
field bookmark names and a calculation in the final cell to add the
other fields in the row. The user had done most of the work, which I
have borrowed for this example, but was having problems with the
calculation.
The modified solution works in a table with seven
columns. The content of the fields in the first six columns is added in
the final column. |
| |
Sub
addrow()
'Works with a seven column table
Dim oTable As
Table
Dim Response As
String
Dim CurRow As Long
Dim i As Long
Dim fCount As Long
Dim
sPassword
as String
Set oTable = ActiveDocument.Tables(1)
sPassword = ""
'Define the password used to protect the
form (if any)
Response = MsgBox("Add new row?", vbQuestion + vbYesNo)
If Response = vbYes Then
ActiveDocument.Unprotect Password:="sPassword"
'Unprotect document
Selection.InsertRowsBelow 1
'Add a row to the bottom of the table
Selection.Collapse (wdCollapseStart)
'Put the cursor in the first cell of the
new row
CurRow =
Selection.Information(wdStartOfRangeRowNumber)
'Read the number of the new row
For i = 1 To oTable.Columns.Count
oTable.Cell(CurRow, i).Select
'Select the next cell for processing
Selection.FormFields.Add Range:=Selection.Range, _
Type:=wdFieldFormTextInput
'And add a form field
fCount = ActiveDocument.Range.FormFields.Count
With ActiveDocument.FormFields(fCount)
.Name = "col" & i & "row" & CurRow
'Add a unique bookmark name
.Enabled = True
'Enable the field for user entry
.CalculateOnExit = True
'set the calculate on exit check box
If i = 6 Then .ExitMacro = "addrow"
'add this macro to the cell in column 6
If i = 7 Then
'add a calculation to add the field
results in cols 1 to 6
.Enabled = False
.TextInput.EditType Type:=wdCalculationText, _
Default:="=Col1Row" & CurRow _
& " + Col2Row" & CurRow _
& " + Col3Row" & CurRow _
& " + Col4Row" & CurRow _
& " + Col5Row" & CurRow _
& " + Col6Row" & CurRow, _
Format:=""
End If
End With
Next i
With ActiveDocument
.Protect NoReset:=True, Password:="sPassword",
_
Type:=wdAllowOnlyFormFields
'Reprotect the form
.Range.FormFields("col1row" & CurRow).Select
'Select the first field in the new row
End With
End If
End Sub
|
|
An alternative
method of adding a row to a protected table |
|
|
The
previous method created the new row in the table and added the
fields to the cells. The following takes an alternative approach and
copies the last row of the table, complete with its fields and
associated macros, and pastes it at the end of the table. It then removes
the on exit macro from what was previously the last row, so that there can be no
false triggering of the macro if a user goes back to amend a field's
content in the last column of a previous row.
The macro makes use of the
wdDialogFormFieldOptions dialog, which has the
following arguments:
Entry, Exit,
Name, Enable,
TextType, TextWidth,
TextDefault, TextFormat,
CheckSize, CheckWidth,
CheckDefault, Type,
OwnHelp, HelpText,
OwnStat, StatText,
Calculate,
to modify the field properties.
As executing this dialog box clears the user entered
result of the field, if that content is later required, as seems
probable, it is necessary to store the content and replace it after
executing the dialog changes. |
| |
Sub
AddRow()
'Run on exit from the last form field in
'the last row of the table
Dim oTable As
Table
Dim oRng As
Range
Dim oCell As
Range
Dim oLastCell As
Range
Dim sResult As String
Dim iRow As
Integer
Dim iCol As Integer
Dim CurRow As Integer
Dim i As Long
Dim
sPassword
as String
sPassword = ""
'password to protect/unprotect
form
With ActiveDocument
.Unprotect Password:=sPassword
'Unprotect document
Set oTable = .Tables(1)
'Select the appropriate table
iRow =
oTable.Rows.Count 'Record the last row number
iCol =
oTable.Columns.Count 'Record the last column
number
Set oLastCell = oTable.Cell(iRow,
iCol).Range 'Record the last cell
sResult =
oLastCell.FormFields(1).Result 'Get the value in
the last cell
Set oRng = oTable.Rows(iRow).Range
'Add the last row to a range
oRng.Copy
'Copy the row
oRng.Collapse
wdCollapseEnd 'collapse the range to its end.
oRng.Select
'the end of the table
Selection.Paste
'Paste the row at the end of the table
CurRow = iRow + 1
'Record the new last row
For i = 1 To
iCol 'Repeat for each column
Set oCell = oTable.Cell(CurRow,
i).Range 'process each cell in the row
oCell.FormFields(1).Select 'Select the
first field in the cell
With
Dialogs(wdDialogFormFieldOptions) 'and name it
.name = "Col" & i & "Row" & CurRow 'eg
Col1Row2
.Execute 'apply the changes
End With
Next i
'Select the formfield in the last cell of the previous row
oLastCell.FormFields(1).Select
With Dialogs(wdDialogFormFieldOptions)
.Exit = "" 'and remove the exit macro
.Execute 'apply the changes
'but note that this clears the value from the cell
End With
oLastCell.FormFields(1).Result = sResult 'so
restore the result of the cell
.Protect NoReset:=True,
Password:=sPassword, _
Type:=wdAllowOnlyFormFields
'Reprotect the form
.FormFields("Col1Row"
& CurRow).Select 'and select the next field to be
completed
End With
End Sub |
|
Create a bar chart based on the content of a
dropdown form field |
|
|
The aim of this procedure is to create a visual
indication, by means of a bar chart, the value of a dropdown form field
as in the animated illustration below. The animation will run
indefinitely: |
|
 |
|
|
Each
of the dropdown fields in column 1 of the table is
configured similarly (create one and copy/paste the remainder). The drop
down entries are numbers 0 to 10, and the macro ColTable1Row1 is run on
exit from each. The illustration shows the default field bookmark name
of Dropdown1. The bookmark names of the fields are immaterial as long as
the final character is a number from 1 to 4 to reflect the row of the
table. This number is used by the macro to fill the correct row of the
table. |
|
 |
| |
Private
mstrFF As String
Sub ColTable1Row1()
Dim oFld As
FormFields
Dim i As
Long
Dim sCount As Integer
Dim sRow As Integer
Dim bProtected As
Boolean
Dim
sPassword
as String
sPassword = ""
'Insert the password (if any), used to
protect the form between the quotes
With GetCurrentFF
'Establish which dropdown field is current
mstrFF =
GetCurrentFF.Name
End With
Set oFld = ActiveDocument.FormFields
sCount = oFld(mstrFF).Result
'Get the dropdown field value
sRow = Right(mstrFF, 1)
'Get the number at the end of the bookmark name
'Check if the document
is protected and if so unprotect it
If
ActiveDocument.ProtectionType <> wdNoProtection
Then
bProtected =
True
ActiveDocument.Unprotect Password:=sPassword
End If
For i = 2
To 11
'Select each column of the active row in turn and
colour the cell white
ActiveDocument.Tables(1).Rows(sRow).Cells(i).Shading.BackgroundPatternColor
= wdColorWhite
Next i
If sCount = 0 Then
GoTo Quit 'If
user enters 0, the row is already white so quit
Select Case sRow
Case 1 'Row 1 colour is
red
oCol = wdColorRed
Case 2 'Row 2 colour is
blue
oCol = wdColorBlue
Case 3 'Row 3 colour is
gold
oCol = wdColorGold
Case 4 'Row 4 colour is
green
oCol = wdColorGreen
Case
Else
End Select
For i = 2 To
sCount + 1 'Colour the
cells in the row from column 2 to the number entered
ActiveDocument.Tables(1).Rows(sRow).Cells(i).Shading.BackgroundPatternColor
= oCol
Next i
Quit: 'Re-protect the
form and apply the password (if any).
If bProtected = True
Then
ActiveDocument.Protect _
Type:=wdAllowOnlyFormFields,
NoReset:=True, Password:=sPassword
End If
End Sub
Private Function GetCurrentFF()
As Word.FormField
'Get the dropdown field
name
Dim rngFF As
Word.Range
Dim fldFF As
Word.FormField
Set rngFF = Selection.Range
rngFF.Expand wdParagraph
For Each fldFF In
rngFF.FormFields
Set GetCurrentFF = fldFF
Exit For
Next
End Function
|
|
Repeat a block
of formatted text and form fields based upon the content of another form
field |
| |
In the
following example a user wished to provide a variable number of fields
and associated formatted text
dependant on a figure input into a form field, as in the following
illustration. For the purpose of the exercise, the control field 'Mortgages'
was set as a number field, the following macro was run on exit from that
field, and the section to be repeated was bookmarked with the name 'bMortgage'.
Note that some of the text is underlined, some is
emboldened and some both underlined and emboldened. There are eight
fields in the selection, each of which will be provided with a new
bookmark name. The bookmark names of the fields in that marked section
will be replaced by the macro, with the names "MortTextn"
where 'i' is a numeric digit from 1 to 8. Subsequent
iterations will be numbered from 8 - 16, 16 -24 etc.
The user may return to the Mortgages field and change the
number and the number of entries will be readjusted to take account of
that changed number. |
|
Note: |
In the illustration, bookmarks are displayed to aid
understanding. |
|

|
| |
Sub
Mortgages()
Dim sNum As Long
Dim oRng As
Range
Dim bProtected As
Boolean
Dim fCount As Long
Dim i As Long
Dim j As Long
'Unprotect the file
If ActiveDocument.ProtectionType <>
wdNoProtection Then
bProtected =
True
ActiveDocument.Unprotect Password:=""
End If
sNum = ActiveDocument.FormFields("Mortgages").Result
Selection.GoTo What:=wdGoToBookmark, Name:="bMortgage"
'Define the range object. This is where the cursor
is at (start point)
Set oRng = Selection.Range
For i = 1 To
sNum
With Selection
'Insert two blank lines
.TypeParagraph
.TypeParagraph
'Set the underline option
.Font.Underline = wdUnderlineSingle
'Set the bold option
.Font.Bold = False
'Ensure that the paragraphs stay together
on the same page
.ParagraphFormat.KeepWithNext = True
.TypeText "Plaintiff: "
.Font.Underline = wdUnderlineNone
'Add a form field
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
.TypeParagraph
.TypeParagraph
.Font.Underline = wdUnderlineSingle
.Font.Bold = True
.TypeText "Mortgage:"
'Turn off the underline
.Font.Underline = wdUnderlineNone
'Turn off the bold option
.Font.Bold = False
.TypeParagraph
.TypeParagraph
.TypeText "From: "
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
.TypeParagraph
.TypeParagraph
.TypeText "To: "
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
.TypeParagraph
.TypeParagraph
.Font.Bold = True
.TypeText "Dated: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
.TypeText Chr(32) 'Add a Space
.Font.Bold = True
.TypeText "Recorded: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
.TypeText Chr(32)
.Font.Bold = True
.TypeText "OR Book: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
.TypeText Chr(32)
.Font.Bold = True
.TypeText "Page: "
.Font.Bold = False
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
.TypeText Chr(32)
.Font.Bold = True
.TypeText "Original Amount: $"
.Font.Bold = False
.FormFields.Add Range:=Selection.Range, Type:=wdFieldFormTextInput
'Turn off the Keep with next option
.ParagraphFormat.KeepWithNext = False
.TypeParagraph
.TypeParagraph
End With
Next i
'The selection has moved down the page. Redefine
the end of the range object.
oRng.End = Selection.Range.End
'Recreate the bookmark.
ActiveDocument.Bookmarks.Add "bMortgage", oRng
'Count the form fields added to the range
fCount = oRng.FormFields.Count
'Give each of the added fields a unique bookmark
name
For j = 1 To
fCount
With oRng.FormFields(j)
.Name = "MortText" & j 'Add a unique
bookmark name
.Enabled = True 'Enable the field for user
entry
.CalculateOnExit = False 'Uncheck the
calculate on exit check box
End With
Next j
'Reprotect the document.
If bProtected = True
Then
ActiveDocument.Protect _
Type:=wdAllowOnlyFormFields,
_
NoReset:=True,
_
Password:=""
End If
'Select the first of the fields in the range
ActiveDocument.FormFields("MortText1").Select
End Sub
|
|
Colour a form
field check box with a contrasting colour when
it is checked. |
|
|
In the
following illustration the checked form field check box is coloured red.
This can be achieved by checking the value of the check box and
formatting the check box when the value is 'True'.
The code uses the function
Private Function GetCurrentFF()
As Word.FormField
used in the Bar Chart example above to
get the current field name, so that the same macro can be applied to the
On Exit property of each check box field. |
| |


|
| |
Private
mstrFF As String
Sub EmphasiseCheckedBox()
Dim oFld As
FormFields
Dim sCount As
Integer
Dim bProtected As
Boolean
Dim sPassword As String
sPassword = "" 'Insert the password (if any), used
to protect the form between the quotes
With GetCurrentFF
'Establish field is current
mstrFF =
GetCurrentFF.name
End With
Set oFld = ActiveDocument.FormFields
sCount = oFld(mstrFF).CheckBox.Value 'Get the
Checkbox field value
'Check if the document is protected and if so
unprotect it
If ActiveDocument.ProtectionType <>
wdNoProtection Then
bProtected =
True
ActiveDocument.Unprotect Password:=sPassword
End If
With oFld(mstrFF).Range
If sCount = True Then
.Font.Color = wdColorRed
'Set the colour of the checked box
Else
.Font.Color = wdColorAutomatic
'Set the colour of the unchecked box
End If
End With
'Re-protect the
form and apply the password (if any).
If bProtected = True
Then
ActiveDocument.Protect _
Type:=wdAllowOnlyFormFields,
NoReset:=True, Password:=sPassword
End If
End Sub
Private Function GetCurrentFF()
As Word.FormField
Dim rngFF As
Word.Range
Dim fldFF As
Word.FormField
Set rngFF = Selection.Range
rngFF.Expand wdParagraph
For Each fldFF In
rngFF.FormFields
Set
GetCurrentFF = fldFF
Exit For
Next
End Function
|
|
Count times entered into a document |
|
|
A user in a Word newsgroup asked how to total the number
of times associated with documented sound bites grouped in sections,
similar to that shown in the illustration below. The macro below will
count all the times in the format HH:MM:SS in the section where the
cursor is located. |
|
 |
|
|
Sub
CountTimes()
'Totals times in the current section
'Times should be in the format HH:MM:SS
Dim sNum As Long
Dim oRng As
Range
Dim sText As String
Dim sHr As Long
Dim sMin As Long
Dim sSec As Long
sHr = 0
sMin = 0
sSec = 0
sNum = Selection.Information(wdActiveEndSectionNumber)
Set oRng = ActiveDocument.Range
With oRng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text =
"[0-9]{2}:[0-9]{2}:[0-9]{2}"
'Look for times in the format 00:00:00
.Wrap = wdFindStop
.MatchWildcards =
True
Do While .Execute =
True
sText = oRng.Text
'To count the whole document, omit the next line
If
oRng.Information(wdActiveEndSectionNumber) = sNum Then
'Split the found time into three separate numbers
'representing hours minutes and seconds and add to
'the previously recorded hours, minutes and seconds
sHr = sHr + Left(sText, 2)
sMin = sMin + Mid(sText, 4, 2)
sSec = sSec + Right(sText, 2)
'To count the whole document, omit the next line
End If
Loop
End With
If sSec > 60 Then
'Divide by 60 and add to the minutes total
sMin = sMin +
Int(sSec / 60)
sSec = sSec
Mod 60 'The remainder
is the seconds
End If
If sMin > 60 Then
'Divide by 60 and add to the hours total
sHr = sHr + Int(sMin
/ 60)
sMin = sMin
Mod 60 'The remainder
is the minutes
End If
MsgBox sHr & " hours" & vbCr & _
format(sMin, "00") & " Minutes" & vbCr & _
format(sSec, "00") & " Seconds"
End Sub
|
|
Transpose Characters |
|
|
There is no
function in Word to transpose the order of two characters - a function
that has been available in some word processing software since before
Windows found its way onto the home computer. The following macro
attached to some suitable keyboard shortcut will correct that omission.
The macro works with either two selected characters or the characters
either side of the cursor. The macro also takes account of the case of the transposed characters.
If the first character to be transposed is upper case and the second
not, then after transposition the first character will be upper case and
the second lower case. Where both or neither characters are upper case,
the case of the characters is retained. |
| |
Sub
Transpose()
Dim oRng As
Range
Dim sText As String
Dim Msg1 As String
Dim Msg2 As String
Dim Msg3 As String
Dim MsgTitle As String
Msg1 = "You must place the cursor between " & _
"the 2 characters to be transposed!"
Msg2 = "There are no characters to transpose?"
Msg3 = "There is no document open!"
MsgTitle = "Transpose Characters"
On Error GoTo ErrorHandler
If ActiveDocument.Characters.Count > 2
Then
Set oRng = Selection.Range
Select Case Len(oRng)
Case Is = 0
If oRng.Start =
oRng.Paragraphs(1).Range.Start Then
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
End If
If oRng.End =
oRng.Paragraphs(1).Range.End - 1 Then
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
End If
With oRng
.Start = .Start - 1
.End = .End + 1
.Select
sText = .Text
End With
Case Is = 1
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
Case Is = 2
sText = Selection.Range.Text
Case Else
MsgBox Msg1, vbCritical, MsgTitle
Exit Sub
End Select
With Selection
If .Range.Characters(1).Case = 1 _
And .Range.Characters(2).Case = 0 Then
.Text = UCase(Mid(sText, 2, 1)) & _
LCase(Mid(sText, 1, 1))
Else
.Text = Mid(sText, 2, 1) & _
Mid(sText, 1, 1)
End If
.Collapse wdCollapseEnd
.Move wdCharacter, -1
End With
Else
MsgBox Msg2,
vbCritical, MsgTitle
End If
ErrorHandler:
If Err.Number = 4248
Then
MsgBox Msg3, vbCritical, MsgTitle
End If
End Sub |
| Insert
Autotext Entry with VBA - Word to 2003 |
|
|
When you
request an autotext entry, Word looks into the active template first,
then in add in templates and finally in the
normal template. This appears rather complex to arrange with vba.
While you
can insert an autotext entry using vba from the attached (active)
template or from the normal template, if it is
present relatively simply,
provided you know its location and it is present.
The problems arise when the location is not known or
may not be present. The following macro first checks whether the
document template is the normal template. If it is not, then the
document template is checked for the entry. If it is or if the entry has
not been found, the macro then checks all installed add-ins. Finally,
if the normal
template was not checked in the first step, it is now
checked. If the entry is found in any of these locations the
entry is inserted and the macro quits. If not
the user is given a message to that effect. |
|
|
Sub
InsertMyAutotext()
Dim oAT As
AutoTextEntry
Dim oTemplate As
Template
Dim oAddin As
AddIn
Dim strText As String
Dim bFound As Boolean
'Define the required autotext entry
strText = "AutoText Name"
'Set the found flag default to False
bFound = False
'Ignore the attached template for now if the
'document is based on the normal template
If ActiveDocument.AttachedTemplate <>
NormalTemplate Then
Set oTemplate = ActiveDocument.AttachedTemplate
'Check each autotext entry in the attached template
For Each oAT In
oTemplate.AutoTextEntries
'Look for the autotext name
If oAT.name = strText Then
'if found insert it
oTemplate.AutoTextEntries(strText).Insert _
Where:=Selection.Range
'Set the found flag to true
bFound = True
'Clean up and stop looking
Set oTemplate = Nothing
Exit Sub
End If
Next oAT
End If
'Autotext entry
was not found
If bFound = False
Then
For Each oAddin In AddIns
'Check currently loaded add-ins
If oAddin.Installed = False Then
Exit For
Set oTemplate = Templates(oAddin.Path & _
Application.PathSeparator & oAddin.name)
'Check each autotext entry in the current attached template
For Each oAT In
oTemplate.AutoTextEntries
If oAT.name = strText Then
'if found insert it
oTemplate.AutoTextEntries(strText).Insert _
Where:=Selection.Range
'Set the found flag to true
bFound = True
'Clean up and stop looking
Set oTemplate = Nothing
Exit Sub
End If
Next oAT
Next oAddin
End If
'The entry has not been found check the normal
template
If bFound = False
Then
For
Each oAT In
NormalTemplate.AutoTextEntries
If oAT.name = strText Then
NormalTemplate.AutoTextEntries(strText).Insert _
Where:=Selection.Range
bFound = True
Exit For
End If
Next oAT
End If
'All sources
have been checked and the entry is still not found
If bFound = False
Then 'so tell the user.
MsgBox "Entry not
found", vbInformation, "Autotext " _
&
Chr(145) & strText & Chr(146)
End If
End Sub |
| Insert Autotext
Entry with VBA - Word 2007/2010 |
|
|
Word 2007
introduced building blocks which added a whole lot of other parameters
and a separate building blocks template where
autotext entries could be stored. Provided the autotext entry that you
wish to insert is defined in the autotext gallery (or it is included in
a Word 97-2003 format template or add-in, then the above macro will work
as it stands. If you want to check all the galleries, then you will need
some extra code. In addition to checking the active template, add-in templates and the
normal template, the following finally looks in the building blocks.dotx
template.
It is to be hoped that if you are using vba to insert
entries, you might have a better idea of where they are stored
beforehand, but this macro should do the trick wherever they are. |
|
|
Sub
InsertMyBuildingBlock()
Dim strText As String
Dim oTemplate As
Template
Dim oAddin As
AddIn
Dim bFound As Boolean
Dim i As Long
'Define the required building block entry
strText = "Building
Block Name"
'Set the found flag default to False
bFound = False
'Ignore the attached template for now if the
'document is based on the normal template
If ActiveDocument.AttachedTemplate <>
NormalTemplate Then
Set oTemplate = ActiveDocument.AttachedTemplate
'Check each building block entry in the attached template
For i = 1 To
oTemplate.BuildingBlockEntries.Count
'Look for the building block name
'and if found, insert it.
If oTemplate.BuildingBlockEntries(i).name = strText
Then
oTemplate.BuildingBlockEntries(strText).Insert _
Where:=Selection.Range
'Set the found flag to true
bFound = True
'Clean up and stop looking
Set oTemplate = Nothing
Exit Sub
End If
Next i
End If
'The entry has
not been found
If bFound = False
Then
For Each
oAddin In AddIns
'Check currently loaded add-ins
If oAddin.Installed = False Then
Exit For
Set oTemplate = Templates(oAddin.Path & _
Application.PathSeparator & oAddin.name)
'Check each building block entry in the each add in
For i = 1 To
oTemplate.BuildingBlockEntries.Count
If oTemplate.BuildingBlockEntries(i).name = strText
Then
'Look for the building block name
'and if found, insert it.
oTemplate.BuildingBlockEntries(strText).Insert _
Where:=Selection.Range
'Set the found flag to true
bFound = True
'Clean up and stop looking
Set oTemplate = Nothing
Exit Sub
End If
Next i
Next oAddin
End If
'The entry has
not been found. Check
the normal template
If bFound = False
Then
For i = 1
To
NormalTemplate.BuildingBlockEntries.Count
If NormalTemplate.BuildingBlockEntries(i).name = strText
Then
NormalTemplate.BuildingBlockEntries(strText).Insert _
Where:=Selection.Range
'set the found flag to true
bFound = True
Exit Sub
End If
Next i
End If
'If the entry
has still not been found
'finally check the Building Blocks.dotx template
If bFound = False
Then
Templates.LoadBuildingBlocks
For Each
oTemplate In Templates
If oTemplate.name = "Building Blocks.dotx"
Then Exit For
Next
For i = 1
To
Templates(oTemplate.FullName).BuildingBlockEntries.Count
If Templates(oTemplate.FullName).BuildingBlockEntries(i).name =
strText Then
Templates(oTemplate.FullName).BuildingBlockEntries(strText).Insert
_
Where:=Selection.Range
'set the found flag to true
bFound = True
'Clean up and stop looking
Set oTemplate = Nothing
Exit Sub
End If
Next i
End If
'All sources have been checked and the entry is
still not found
If
bFound = False Then
'so tell the user.
MsgBox "Entry not
found", vbInformation, "Building Block " _
&
Chr(145) & strText & Chr(146)
End If
End Sub
|
|
Replace various words or phrases in a document from a table list,
with a choice of replacements |
|
|
It is
fairly straightforward to use vba to search for a series of words or
phrases from an array or from
a document containing a table (or a list
comprising each item in a separate paragraph) and then either processing
the found words or replacing them with a corresponding word in the
adjacent column of the same table. The following
examples will do each of those things: |
| Replace a list of
words from an array |
|
|
The following example uses a pair of arrays to hold
corresponding lists of words, characters or phrases separated by commas.
Items from the first list are replaced with the corresponding item from
the second list
vFindText =
Array(Chr(147), Chr(148), Chr(145), Chr(146))
vReplText = Array(Chr(34), Chr(34), Chr(39), Chr(39))
In a practical use of the technique, the above example as
shown in the macro below, is used to replace smart quotes with straight
quotes (and vice versa), however the list and macro could be modified to
be used to replace or process any sequence of words or phrases. |
|
|
Sub
ReplaceQuotes()
Dim vFindText As
Variant
Dim vReplText As
Variant
Dim sFormat As
Boolean
Dim sQuotes As String
Dim i As Long
'Ask the user whether
to format with smart or straight quotes
sQuotes = MsgBox("Click 'Yes' to convert smart quotes to straight
quotes." & vbCr & _
"Click 'No' to convert straight quotes to smart quotes.", _
vbYesNo, "Convert quotes")
'Record the current
setting of the autoformat option to replace straight quotes with smart
quotes
sFormat = Options.AutoFormatAsYouTypeReplaceQuotes
If sQuotes = vbYes
Then 'The user
has clicked 'Yes'
'Define the lists of smart quotes and their
replacements
vFindText =
Array(Chr(147), Chr(148), Chr(145), Chr(146))
vReplText =
Array(Chr(34), Chr(34), Chr(39), Chr(39))
'Set the
autoformat option to replace straight quotes with smart quotes
to off
Options.AutoFormatAsYouTypeReplaceQuotes = False
'Start from the top of the document
Selection.HomeKey
wdStory
With Selection.Find
.Forward = True
.Wrap = wdFindContinue
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Format = True
.MatchCase = True
'replace
each item from the first array with the corresponding item in the second
array
For i = LBound(vFindText) To
UBound(vFindText)
.Text = vFindText(i)
.Replacement.Text = vReplText(i)
.Execute Replace:=wdReplaceAll
Next i
End With
Else 'User
clicked 'No'
'Use
autoformat to replace straight quotes with smart quotes
Options.AutoFormatReplaceQuotes =
True
Selection.Range.AutoFormat
End If
'Finally reset the
autoformat setting to its start configuration
Options.AutoFormatAsYouTypeReplaceQuotes = sFormat
End Sub |
| Replace a list of
words from a table |
|
|
In the
following example, the words and their replacements are stored in
adjacent columns of a two column table stored in a
document - here called "changes.doc". The name is unimportant and
Word 2007/2010 users could use docx format.
The table could also
have more than two columns, but only the first two columns are
used. |
|
|
Sub
ReplaceFromTableList()
Dim ChangeDoc, RefDoc
As Document
Dim cTable As
Table
Dim oFind, oReplace
As Range
Dim i As
Long
Dim sFname As String
'Define the document containing the table of
words/phrases and their replacements
sFname = "D:\My Documents\Test\changes.doc"
'Define the document
to be processed
Set RefDoc = ActiveDocument
'Open the
document with the changes
Set ChangeDoc = Documents.Open(sFname)
'Define the table to
be used
Set cTable = ChangeDoc.Tables(1)
'Activate the document
to be processed
RefDoc.Activate
For i = 1 To
cTable.Rows.Count
'Define the cell containing
the word/phrase to be replaced
Set oFind = cTable.Cell(i, 1).Range
oFind.End = oFind.End
- 1
'Define the cell containing the replacement
word/phrase
Set oReplace = cTable.Cell(i, 2).Range
oReplace.End =
oReplace.End - 1
With Selection
'Start at the top of the document
.HomeKey wdStory
'Replace the words/phrases
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Execute findText:=oFind, _
ReplaceWith:=oReplace, _
Replace:=wdReplaceAll, _
MatchWholeWord:=True,
_
MatchWildcards:=False,
_
MatchCase:=True,
_
Forward:=True,
_
Wrap:=wdFindContinue
End With
End With
Next i
'Close the
document with the table
ChangeDoc.Close wdDoNotSaveChanges
End Sub |
| Replace a list of
words from a table and offer a choice of replacements |
|
|
The final example in this trilogy of replacements using
lists was prompted by a newsgroup question. The user wanted initially to
highlight words and phrases in a document from a list, which was easily
achieved using a variation of one of the above macros, and the he
ventured the possibility of the user choosing from a number of possible
replacements. How practical this is in a real life situation I cannot
say, but the principles involved I felt were interesting enough to
repeat them here.
In this instance the macro uses a multi-column table. The
first column contains the words to be located, the subsequent columns
contain the replacement choices. The columns should be filled from left
to right. Not all the columns (except the first) need contain any data,
but the columns must be filled from left to right with no gaps.
If only the second column has data, the found item is
replaced with the content of the second column
If more columns to the right of the second column have
data, the choices from the second and subsequent columns are presented
as numbered choices in a list.
If none of the columns, except the first, contains data,
then the found word is merely highlighted.
There must be no empty cells in the first column! |
|
|
Sub
ReplaceFromTableChoices()
Dim ChangeDoc,
RefDoc As Document
Dim cTable As
Table
Dim oldPart, newPart, oFound
As Range
Dim i, j, iCol As
Long
Dim sFname, sReplaceText, sNum
As String
'Define the document containing the table of
changes.
'The table must have
at least 3 columns.
sFname = "D:\My Documents\Test\changes2.doc"
'Define the document
to be processed
Set RefDoc = ActiveDocument
Set ChangeDoc = Documents.Open(sFname)
'Define the table to
be used
Set cTable = ChangeDoc.Tables(1)
'Activate the document
to be processed
RefDoc.Activate
'Process each row of
the table in turn
For i = 1
To cTable.Rows.Count
'Set the search item to the content of the first cell
Set oldPart = cTable.Cell(i, 1).Range
'Remove the cell end character from the range
oldPart.End =
oldPart.End - 1
'Start from the beginning of the document
With Selection
.HomeKey wdStory
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.MatchWholeWord = True
.MatchCase = True
'Look for the search item
Do While .Execute(findText:=oldPart)
'And assign the found item to a range variable
Set oFound = Selection.Range
'Set the start number of a counter
iCol = 1
'Set a temporary
replacement text string to zero length
sReplaceText = ""
'Look into the remaining columns for replacement choices
For j = 2 To
cTable.Columns.Count
'And assign the replacement choices to a range variable in turn
Set newPart = cTable.Cell(i, j).Range
'Remove the cell end character from the range
newPart.End = newPart.End - 1
'If the current cell has no content, ignore the remainder
If Len(newPart) = 0 Then Exit For
'Add the range content to the
temporary replacement text string
sReplaceText = sReplaceText & iCol & ". " & _
newPart.Text & vbCr
'Increment the counter
iCol = iCol + 1
Next j
'If there is a replacement available
If Len(sReplaceText) <> 0 Then
'If there is only one such replacement
If Len(cTable.Cell(i, 2).Range) <> 2
And _
Len(cTable.Cell(i, 3).Range) = 2 Then
'Set the number of that replacement to 1
sNum = "1"
Else
Again: 'Add a label to
mark the start of the user input
'If there is more than one choice,
'ask the
user to pick the preferred replacement
sNum = InputBox(sReplaceText & vbCr & vbCr & _
"Enter the number of the replacement for '" _
& oldPart.Text & "'")
If sNum = "" Then Exit Sub
'The user has cancelled
'Error trap inappropriate user choices
'Check if the user has entered something other than a number
If IsNumeric(sNum) = False Then
'Tell the user
MsgBox "Invalid entry! Try again.", _
vbInformation, "Error"
'and go round again
GoTo Again
End If
'Check if the user has entered a number
'higher
than the number of columns in the table
If sNum > cTable.Columns.Count Then
'Tell the user
MsgBox "Invalid entry! Try again.", _
vbInformation, "Error"
'and go round again
GoTo Again
End If
'Check if a user has picked a valid
number
'higher
than the available choices
If Len(cTable.Cell(i, sNum + 1).Range) = 2
Then
'Tell
the user
MsgBox "Invalid entry! Try again.", _
vbInformation, "Error"
'and go round again
GoTo Again
End If
End If
'Set the replacement according to the user
input
Set newPart = cTable.Cell(i, sNum + 1).Range
newPart.End = newPart.End - 1
oFound.Text = newPart.Text
Else
'There are no replacements so highlight the found item
oFound.HighlightColorIndex = wdYellow
End If
Loop
End With
End With
Next i
'Close the document
containing the table
ChangeDoc.Close wdDoNotSaveChanges
End Sub
|
|
Add tabs to centre of text area and
right margin |
|
|
The
following macro sets a centre aligned tab, centred between the current
margins, and a right aligned tab at the right margin. |
|
|
Sub
AddTabs()
Dim iLeft As Long
Dim iRight As Long
Dim iCentre As Long
Dim iWidth As Long
With Selection
iLeft =
.Sections(1).PageSetup.LeftMargin
iRight =
.Sections(1).PageSetup.RightMargin
iWidth =
.Sections(1).PageSetup.PageWidth
iCentre = (iWidth -
iLeft - iRight) / 2
.ParagraphFormat.TabStops.Add
Position:=iCentre, _
Alignment:=wdAlignTabCenter, _
Leader:=wdTabLeaderSpaces
.ParagraphFormat.TabStops.Add
Position:=iWidth - (iRight + iLeft), _
Alignment:=wdAlignTabRight, _
Leader:=wdTabLeaderSpaces
End With
End Sub |
| |
|
|