I am composing a word .doc using access VBA. Doc starts in one column. I split the next section into 3 columns using:
.InsertBreak wdSectionBreakContinuous
With w.ActiveDocument.Sections(2).PageSetup.TextColumns
.SetCount numcolumns:=2
.Add EvenlySpaced:=True
End With
Then I split to 2 columns using:
.InsertBreak wdSectionBreakContinuous
With w.ActiveDocument.Sections(3).PageSetup.TextColumns
.SetCount numcolumns:=1
.Add EvenlySpaced:=True
End With
Now I want to go back to a single column, but the following:
.InsertBreak wdSectionBreakContinuous
w.ActiveDocument.Sections(4).PageSetup.TextColumns.SetCount numcolumns:=0
does not work. Any tips on how to convert back to a single column?
FWIW all of this happens on a single page in word.
Thanks!
This works for me:
Sub ColumnsDemo()
Dim Rng As Range
With ActiveDocument
With .Sections(1)
.PageSetup.TextColumns.SetCount NumColumns:=1
Set Rng = .Range.Paragraphs(10).Range
Rng.Collapse
Rng.InsertBreak wdSectionBreakContinuous
End With
With .Sections(2)
With .PageSetup.TextColumns
.SetCount NumColumns:=2
.EvenlySpaced = True
.LineBetween = False
End With
Set Rng = .Range.Paragraphs(10).Range
Rng.Collapse
Rng.InsertBreak wdSectionBreakContinuous
End With
With .Sections(3)
With .PageSetup.TextColumns
.SetCount NumColumns:=3
.EvenlySpaced = True
End With
Set Rng = .Range.Paragraphs(10).Range
Rng.Collapse
Rng.InsertBreak wdSectionBreakContinuous
End With
With .Sections(4)
With .PageSetup.TextColumns
.SetCount NumColumns:=2
.EvenlySpaced = True
.LineBetween = False
End With
Set Rng = .Range.Paragraphs(10).Range
Rng.Collapse
Rng.InsertBreak wdSectionBreakContinuous
End With
With .Sections(5)
.PageSetup.TextColumns.SetCount NumColumns:=1
End With
End With
End Sub
You need at least to use
w.ActiveDocument.Sections(4).PageSetup.TextColumns.SetCount numcolumns:=1
rather than numcolumns:=0
Here, using numcolumns:=1 raises error 5148 "The number must be between 1 and 45", which suggests that you may have switched off error checking while testing your code.
Also, if you compare with your first two pieces of code, you are
setting the number of columns to 2, then Adding a column to make 3
setting the number of columns to 1, then Adding a column to make 2
whereas in your third piece of code you aren't Adding a column, suggesting that you would need in any case to set the count to 1 rather than 0.
New material
Your original code snippets don't say what objects/ranges your .InsertBreak method calls are applied to. If you start with a blank document, you might well be inserting all your section breaks at the beginning of the document, which would definitel cause problems.
Another possible problem is that when you have multiple columns, it isn't necessarily obvious which paragraphs are in which section.
macropod's code works fine here, and I get the 1,2,3,2,1 column sections you would expect, not the 2,3,4,3,2 that you are seeing. There's no reason to believe that it would be any different running the code from Access (in fact I tried it with the necessary changes, just to be sure).
But maybe the following code will make some things clearer.
Sub BuildDoc()
Dim r As Word.Range
' Assume we're starting from a completely blank document.
With ActiveDocument
' Let's ensure it has 1 column
.PageSetup.TextColumns.SetCount NumColumns:=1
' Let's work with a range variable
Set r = .Content
' add a bit of text and some paragraphs
' to create a visible section 1
'
r.Text = "Start section 1"
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
' At this point, r still has the same start and end as .content
' If we inserted a section break now using r or .COntent,
' it would be inserted at the beginning of the document
' So let's just collapse r to its and and add a bit more text
' before starting the new section
' We can "get to the right place" this way
r.Collapse WdCollapseDirection.wdCollapseEnd
r.Text = "End section 1"
r.Collapse WdCollapseDirection.wdCollapseEnd
' This inserts the break before the final paragraph mark
r.InsertBreak wdSectionBreakContinuous
' r now starts *after* the break
With r.PageSetup.TextColumns
.SetCount NumColumns:=3
.EvenlySpaced = True
End With
' add some text and paras
r.Text = "Start section 2"
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
' and repeat for a 2-column section
r.Collapse WdCollapseDirection.wdCollapseEnd
r.Text = "End section 2"
r.Collapse WdCollapseDirection.wdCollapseEnd
r.InsertBreak wdSectionBreakContinuous
' r now starts *after* the break
With r.PageSetup.TextColumns
.SetCount NumColumns:=2
.EvenlySpaced = True
End With
' add some text and paras
r.Text = "Start section 3"
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
' and back to 1 column
r.Collapse WdCollapseDirection.wdCollapseEnd
r.Text = "End section 3"
r.Collapse WdCollapseDirection.wdCollapseEnd
r.InsertBreak wdSectionBreakContinuous
' r now starts *after* the break
With r.PageSetup.TextColumns
.SetCount NumColumns:=1
End With
' add some text and paras
r.Text = "Start section 4"
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Paragraphs.Add
r.Collapse WdCollapseDirection.wdCollapseEnd
r.Text = "End section 4"
End With
End Sub
If you run that in Word, you should get the section layout you were trying to achieve. If you don't, combined with the result you had with macropod's code, I'd suggest that something else is going on, such as document or template corruption.
Here, that ends up looking like this:
WHen I first looked at this I thought "why is there an extra paragraph at the beginning of section 4, before the text "Start section 4" ? CLick in it, check the column count, and it says "2".
But of course the paragraph isn't in Section 4, it's in the first column ofSection 3. It's just my eyesight playing tricks.
Related
I have a Word application which generates a document containing a boatload of Word tables and nothing else. In the end, I want a single table containing hundreds of rows which could potentially spread over a couple hundred pages. However, it is far easier to generate this document a table at a time with some sort of a break, be it a page break or continuous section break, between tables.
While the tables are numerous, they all contain multiple rows with two columns taking up 20% and 80% of the width. Row 1 always has both cells merged. I've found that having merged cells impacts performance such that some operations, here the width setting, sporadically fail. Adding a DoEvents or delay between iterations helps somewhat, but the best thing I've found for this is to do the cell merge for all the tables after they have been initially built.
Now that the document containing all the tables has been generated, what's a "better" way to remove the section breaks such that all the tables become fused together as one?
This has worked for me, first to attempt removing the breaks with something like this:
With ActiveDocument.Content.Find
.ClearAllFuzzyOptions
.ClearFormatting
.Text = "^m" ' for page breaks
' .Text = "^b" ' when searching for continuous section breaks
.Replacement.Text = ""
.Execute Replace:=WdReplace.wdReplaceAll
End With
Interestingly, when a continuous section break is used, this code fragment only removes the very last occurrence, as does the replace facility in the Word ribbon. When a page break is used, all page breaks are removed, however this leaves two stray paragraphs between tables. These can be cleaned up with something like the following:
For i = ActiveDocument.Paragraphs.Count To 1 Step -1
If Not ActiveDocument.Paragraphs(i).Range.Information(wdWithInTable) Then
ActiveDocument.Paragraphs(i).Range.Delete
End If
Next i
This works but is understandably rather slow. (There are some 4000 paragraphs in total, 50 of which are candidates for removal)
In the end, using page breaks plus cleanup works but is very slow. Ideally, the first code fragment should work with continuous section breaks, which should require no downstream cleanup. Suggestions?
This is using MS Office 2016.
This program replicates the problem on my system.
Public Sub test()
Dim Word As Word.Application: Set Word = New Word.Application
Dim i As Integer, j As Integer, k As Integer
Word.Visible = True
Word.Activate
Word.ScreenUpdating = True
Word.Documents.Add
Dim c As Integer
Dim t As Integer: t = 0
Dim myrange As Word.Range: Set myrange = ActiveDocument.Content
myrange.Collapse Direction:=wdCollapseEnd
For j = 0 To 25
' depending on a blank row, add either a single row or rows for all the countries' answers
t = t + 1
ActiveDocument.Tables.Add Range:=myrange, NumRows:=25 + 2, NumColumns:=2
With ActiveDocument.Tables(t)
.rows(1).Cells(1).Range.Text = "Header " & j
.Borders.Enable = True
.Columns(1).PreferredWidthType = wdPreferredWidthPercent
.Columns(1).PreferredWidth = 20
.Columns(2).PreferredWidthType = wdPreferredWidthPercent
.Columns(2).PreferredWidth = 80
End With
For i = 0 To 25
With ActiveDocument.Tables(t).rows(i + 2)
.Cells(1).Range.Text = "Text " & i & " " & j
.Cells(2).Range.Text = "More Text " & i & " " & j
End With
DoEvents
Next i
Set myrange = ActiveDocument.Content
myrange.Collapse Direction:=wdCollapseEnd
myrange.InsertBreak Type:=wdSectionBreakContinuous
Next j
' fix up row 1 for all tables
For i = 1 To ActiveDocument.Tables.Count
With ActiveDocument.Tables(i)
.rows(1).Cells.Merge
.rows(1).Cells(1).Range.Style = "Heading 3"
.rows(1).Cells(1).Shading.BackgroundPatternColor = wdColorGray25
End With
DoEvents
Next i
With ActiveDocument.Content.Find
.ClearAllFuzzyOptions
.ClearFormatting
.Text = "^b"
.Replacement.Text = ""
.Execute Replace:=WdReplace.wdReplaceAll
End With
For i = Word.ActiveDocument.Paragraphs.Count To 1 Step -1
If Not Word.ActiveDocument.Paragraphs(i).Range.Information(wdWithInTable) Then
Word.ActiveDocument.Paragraphs(i).Range.Delete
End If
Next i
End Sub
I have a paragraph like this:
Nov 19, 2014 - You are running the search on the Selection, but you're
not changing that selection between runs. So you just end up making
the same text bold over and over again. Here's a way to do what you're
doing without the Selection object: Sub ParaStyle() Dim objPara As
Paragraph For Each objPara In ... Word VBA Paragraph
formatting-VBForums
And I am trying to change the style of the entire paragraph to a local style. I am using the following code:
Dim rgePages As Range
Dim p As Paragraph
Selection.GoTo What:=wdGoToPage, Which:=wdGoToAbsolute, Count:=3
Set rgePages = Selection.Range
Selection.GoTo What:=wdGoToPage, Which:=wdGoToAbsolute, Count:=6
rgePages.End = Selection.Bookmarks("\Page").Range.End
rgePages.Select
For Each p In rgePages.Paragraphs
If p.Style <> "Heading 1" Then
p.Style = "Body Text"
'p.Style = Word.WdBuiltinStyle.wdStyleBodyText
rgePages.Collapse Word.WdCollapseDirection.wdCollapseEnd
End If
Next
It is working fine till the time any line or a few words are in different style. Say for example if the line
So you just end up making
in the paragraph is in different style, it is marking the whole paragraph as "Body Text" except for that part. Is there a solution to this?
You could try to clear formatting first before you apply your own style. It could go this way:
....
If p.Style <> "Heading 1" Then
p.Range.Select
Selection.ClearFormatting 'it rather works with selection only
p.Style = "Body Text"
....
I'm new to VBA and would greatly appreciate some help on a problem.
I have long Word documents where I need to apply standard comments to the same set of keywords, but only in selected sections of the document. The following macro worked to find a keyword and apply a comment (from question here https://superuser.com/questions/547710/macro-to-insert-comment-bubbles-in-microsoft-word):
Sub label_items()
'
' label_items Macro
'
'
Do While Selection.Find.Execute("keyword1") = True
ActiveDocument.Comments.Add range:=Selection.range, Text:="comment for keyword 1"
Loop
End Sub
The two modifications are:
1) only apply the comments to user selected text, not the whole document. I tried a "With Selection.Range.Find" approach but I don't think comments can be added this way (??)
2) repeat this for 20+ keywords in the selected text. The keywords aren't totally standard and have names like P_1HAI10, P_1HAI20, P_2HAI60, P_HFS10, etc.
EDIT: I have tried to combine code from similar questions ( Word VBA: finding a set of words and inserting predefined comments and Word macro, storing the current selection (VBA)) but my current attempt (below) only runs for the first keyword and comment and runs over the entire document, not just the text I have highlighted/selected.
Sub label_items()
'
' label_items Macro
'
Dim selbkup As range
Set selbkup = ActiveDocument.range(Selection.range.Start, Selection.range.End)
Set range = selbkup
Do While range.Find.Execute("keyword 1") = True
ActiveDocument.Comments.Add range, "comment for keyword 1"
Loop
Set range = selbkup
Do While range.Find.Execute("keyword 2") = True
ActiveDocument.Comments.Add range, "comment for keyword 2"
Loop
'I would repeat this process for all of my keywords
End Sub
I've combed through previous questions and the Office Dev Center and am stuck. Any help/guidance is greatly appreciated!
It's a matter of adding a loop and a means of Finding the next keyword you're looking for. There are a few suggestions in the code example below, so please adjust it as necessary to fit your requirements.
Option Explicit
Sub label_items()
Dim myDoc As Document
Dim targetRange As Range
Set myDoc = ActiveDocument
Set targetRange = Selection.Range
'--- drop a bookmark to return the cursor to it's original location
Const RETURN_BM = "OrigCursorLoc"
myDoc.Bookmarks.Add Name:=RETURN_BM, Range:=Selection.Range
'--- if nothing is selected, then search the whole document
If Selection.Start = Selection.End Then
Selection.Start = 0
targetRange.Start = 0
targetRange.End = myDoc.Range.End
End If
'--- build list of keywords to search
Dim keywords() As String
keywords = Split("SMS,HTTP,SMTP", ",", , vbTextCompare)
'--- search for all keywords within the user selected range
Dim i As Long
For i = 0 To UBound(keywords)
'--- set the cursor back to the beginning of the
' originally selected range
Selection.GoTo What:=wdGoToBookmark, Name:=RETURN_BM
Do
With Selection.Find
.Forward = True
.Wrap = wdFindStop
.Text = keywords(i)
.Execute
If .Found Then
If (Selection.Start < targetRange.End) Then
Selection.Comments.Add Selection.Range, _
Text:="Found the " & keywords(i) & " keyword"
Else
Exit Do
End If
Else
Exit Do
End If
End With
Loop
Next i
'--- set the cursor back to the beginning of the
' originally selected range
Selection.GoTo What:=wdGoToBookmark, Name:=RETURN_BM
End Sub
I am working on a macro in word. It pulls cell contents from some cells in an excel doc, puts part of them at the end of the word doc, bolds the first part, then puts the rest of the string and unbolds it.Then it looks for the next match in the excel doc and repeats until there are no matches.
On the second pass through the loop, it continues to affect the content added in the first pass. The font with block also affects the previous line and ends up bolding the entire thing. I set the object to Nothing at the end of the function so I wouldn't expect it to see the first part of the loop as part of the range any longer.
Do
x = AssembleSentence(Last, First, Rank)
Set Loc = .FindNext(Loc)
Loop While Not Loc Is Nothing And Loc.Address <> sFirstFind
Function AssembleSentence(Last, First, Rank)
Dim sText0 As String, sText As String, oText As Object
Set oText = ActiveDocument.Content
sText0 = First & " " & Last
sText = ", " & Rank & " Professor at College of Hard Knocks."
Set oText = ActiveDocument.Content.Paragraphs.Add
oText.Range.SetRange Start:=ActiveDocument.Range.End, End:=ActiveDocument.Range.End
Selection.EndKey Unit:=wdStory
With oText.Range
.InsertAfter (sText0)
With .Font
.Bold = True
End With
End With
Selection.EndKey Unit:=wdStory
With Selection
.Text = sText
With .Font
.Bold = False
End With
End With
Selection.EndKey Unit:=wdStory
Set oText = Nothing
End Function
Still unsure why the loop doesn't redo the range to the end on its own, but this fixes it so that it stops affecting prior looped content.
Looking at my oText.range start/end properties it looks like it is 1034/1035 with a length of 1036 on the first pass and then 1036/1209 with a length of 1210 on the second pass. That is the issue - I don't know why it isn't 1208/1209 on the second pass after setting the object to nothing at the end of the first pass, but the following edit fixes the issue.
With oText.Range
.SetRange Start:=oText.Range.End, End:=oText.Range.End
.InsertAfter (sText0)
With .Font
.Bold = True
End With
End With
I need to loop through all the headings in the document and need to add new heading between Heading-2 and Heading-3. All existing headings are Heading 1 and I know the text.
I need to delete Heading-5.
The original file has 30000 more paragraphs; using old method takes too much time
for example here are the headings
1. Heading-1
2. Heading-2
3. Heading-3
4. Heading-4
5. Heading-5
6. Heading-6
For P = 1 To ActiveDocument.Paragraphs.Count - 1
ptext=ActiveDocument.Paragraphs(p).text
If Left(ActiveDocument.Paragraphs(P).Style, 9) = "Heading 1" Then
If InStr(1, ptext, "Heading-2") > 0 Then
ActiveDocument.Paragraphs.Add _
Range:=ActiveDocument.Paragraphs(P).Range
Selection.MoveLeft Unit:=wdCharacter, Count:=1
Selection.TypeText Text:="Heading New"
End If
End If
Next
In that case, record a macro in Word for the following steps:
In the Find dialog enter the text for "Heading-3" then click "find". The selection should jump to Heading-3
This will give you the basic syntax for going to Heading 3. You can edit it to remove parameters you don't want/need (you only need the text search, really).
Following the Find you insert code that will create a new paragraph with the text you want. There are a number of ways this can be done, my preference:
Dim rng as Word.Range
Set rng = Selection.Range
rng.InsertBefore vbCr 'paragraph mark
rng.Collapse wdCollapseStart
rng.Text = "NEW STUFF"