Log in

View Full Version : Solved: Need help with searching for a style and then inserting column break



janaboo13
07-12-2011, 02:49 PM
Greetings all! It's been a while since I've been doing any coding, but I'm stumped and need help.

I need to search a Word document for a particular style and when found, let the user indicate whether or not they want to insert a column break.

I can get the search part of the code, but I need help with the user input side of things.

Any suggestions?

Many thanks! Jan:banghead:

Frosty
07-14-2011, 12:49 PM
I would be much easier to insert the "right" answer if you posted what you already have. Something along the following lines may be all you need.


'messagebox which defaults to "no"
If MsgBox("Insert a Column Break?", vbQuestion + vbYesNo + vbDefaultButton2, "My Title") = vbYes Then
'insert the column break at your .Found range
End If

Talis
07-14-2011, 12:54 PM
Try this:
Sub StylesParaBreak()
Dim myStyle As String
'Selection.HomeKey Unit:=wdStory 'UNCOMMENT if you always want to start at beginning

myStyle = "Heading 2" 'replace with the desired style
For Each oPara In ActiveDocument.Paragraphs
If oPara.Style = myStyle Then
oPara.Range.Select
Select Case MsgBox("Enter a column break before this paragraph?", vbYesNoCancel, "Break?")
Case 2
GoTo abort
Case 6
With oPara.Range
.Collapse Direction:=wdCollapseStart 'change to wdCollapseEnd if wanted after and modify MsgBox prompt in line above
.InsertBreak Type:=wdColumnBreak
End With
Case 7
GoTo continue
End Select
End If
continue:
Next
abort:
End Sub

I'm assuming that the style in question is a paragraph style and that you want to insert the break before the found style. If not the latter it should be fairly obvious what to change.

janaboo13
07-14-2011, 01:34 PM
Thank you Talis! I'm working on this now and I think this will do it!

Frosty, I know I didn't give you enough info...turns out what I had didn't work anyway...sorry!

Jan

Frosty
07-14-2011, 01:41 PM
Clarification in Talis' code:

Uncommenting the Selection.Homekey line of code will have no effect on a For Each...Loop which iterates through ActiveDocument.Paragraphs. Regardless of where your selection (cursor) is, you will cycle through the paragraphs in the document starting from the first and ending up at the last.

janaboo13
07-14-2011, 02:11 PM
Hi All!
Talis' solution worked great. I have modified the code a bit, however, and need a little more help buttoning it up. We have our docs open to two pages and when I run this macro, I set the view to zoom to page width.

I'd like to reset the view back to two pages when done, and am having brain freeze. Can you help?

Here's the code that I'm using now:

Sub StylesParaBreak()
Dim myStyle As String

ActiveWindow.ActivePane.View.Zoom.PageFit = wdPageFitBestFit

Selection.HomeKey Unit:=wdStory 'UNCOMMENT if you always want to start at beginning

myStyle = "Table Break" 'replace with the desired style
For Each oPara In ActiveDocument.Paragraphs
If oPara.Style = myStyle Then
oPara.Range.Select
Select Case MsgBox("Enter a column break here?", vbYesNoCancel, "Break?")
Case 2
GoTo abort
Case 6
With oPara.Range
.Collapse Direction:=wdCollapseStart 'change to wdCollapseEnd if wanted after and modify MsgBox prompt in line above
.InsertBreak Type:=wdColumnBreak
End With
Case 7
GoTo continue
End Select
End If
continue:
Next
abort:
End Sub

Thanks in advance! Jan

Frosty
07-14-2011, 02:24 PM
Take out

ActiveWindow.ActivePane.View.Zoom.PageFit = wdPageFitBestFit
and
Selection.HomeKey Unit:wdStory

I don't have anything but Word2003 at the moment, so the only options there are:
wdPageFitBestFit
wdPageFitFullPage
wdPageFitNone
wdPageFitTextFit

But this is a good opportunity to learn about the object browser for yourself.

In the VBA IDE, hit F2 (the Object Browser will come up).

Search in <All Libraries> for "PageFit" (which is the property you want to learn about).

You'll see a list come up, and you want to look for what members of the wdPageFit enumeration are... you'll probably see the one you want.

However, the best way to do this (if you still want to change the .PageFit property at the top of your routine to something specific for purposes of selecting the paragraph in the middle of your For Each... Loop), is to store whatever the current .PageFit is before you change it, and then restore it... a la...

Dim lOrigPageFit As WdPageFit

lOrigPageFit = ActiveWindow.View.Zoom.PageFit
ActiveWindow.View.Zoom.PageFit = wdPageFitBestFit
'the rest of your routine

ActiveWindow.View.Zoom.PageFit = lOrigPageFit

Instead of assuming how your user starts the routine, it's better to store whatever it is and then restore it later.

Frosty
07-14-2011, 02:37 PM
Incidentally... depending on the length of the document, a For Each... Loop iterating through all of the paragraphs will be slower than using the .Find object (especially if, for example, there are big, complicated tables in your document).

In my own tests, there is also a flaw in this process if there is an existing column break and you are in a one column section (you'll only see that the paragraph is at the top of a page, but won't know if that's luck or because there is already a column break at the beginning of the range).

Here's an alternative bit of code which basdically works the same way.


Sub SearchForStyleAndAskToInsertColumn()
Dim rngSearch As Range
Dim lOrigPageFit As WdPageFit
'store
lOrigPageFit = ActiveWindow.View.Zoom.PageFit
'change
ActiveWindow.View.Zoom.PageFit = wdPageFitBestFit
'set up our search
Set rngSearch = ActiveDocument.Content
With rngSearch.Find
.Style = "Heading 1"
'while we find it...
Do While .Execute = True
'select
rngSearch.Select
'messagebox which defaults to "no"
Select Case MsgBox("Insert a Column Break?", vbQuestion + vbYesNoCancel + vbDefaultButton2, "My Title")
Case vbYes
rngSearch.Collapse wdCollapseStart
rngSearch.InsertBreak Type:=wdColumnBreak

Case vbNo
'do nothing, but continue our loop
Case vbCancel
'exit our loop
Exit Do
Case Else
Stop
'always good habit to use a Case Else
End Select
Loop
End With

'restore
ActiveWindow.View.Zoom.PageFit = lOrigPageFit

End Sub

Be careful with using Go To frequently, it will occasionally cause you problems if your routines become complex and you haven't thought out exactly every item (i.e., if you put your ActiveWindow.View.Zoom.PageFit = lOrigPageFit in front of your abort: label, if the user hits cancel he/she won't get his original view restored).

You may want to test the beginning of your rngSearch within the find to see if the first character is a column break or not... something along the lines of

'if the first character isn't already a column break then
If rngSearch.Characters.First <> Chr(14)
'collapse the range and insert the column break
End If

Talis
07-14-2011, 11:43 PM
I bow to the far superior knowledge of Frosty.

janaboo13
07-15-2011, 07:23 AM
Hi Frosty!
Thank you so much for some much needed education...I'm getting the hang of using F2! YEAH!

Your solution works great and at the end, the restore works. Now, to throw a little kink into things. I have the following in my AutoOpen macro:

' Change view of window to Print View and set facing pages
With ActiveWindow.View
.Type = wdPrintView
With .Zoom
.PageColumns = 2
.PageRows = 1
End With
End With

My writers want to see two facing pages so they can do necessary copy editing and layout modifications (they are also used to using PageMaker), so I want to make them happy. It would be nice if the restore would take them back to this view...any suggestions???

Again, thank you so much! While on th subject, do you know of any online courses that help folks like me who are just learning VBA?

Jan :friends:

Frosty
07-15-2011, 09:05 AM
I have seen "MindLeaders" as an online resource offered by one of my jobs, but by the time I encountered it, I was a bit ahead of their programming offerings. But it seemed like a good online tutoring program. However, as a (mostly) self-taught programmer who had the occasional mentor help, I think your best resource is simply a combination of patience and desire. And knowing when to ask for help :)

As for your coding question: probably best to encapsulate that functionality, and then call it whenever you want. My sample was simply a "typical" best practice (i.e., leaving things the way you find them). However, each project has different needs. If your users want to have the view 'reset' to the standard view after running the InsertColumns function, I'd suggest doing this:

Public Sub SetMyView
With ActiveWindow.View
.Type = wdPrintView
With .Zoom
.PageColumns = 2
.PageRows = 1
End With
End With
End Sub

And then put "SetMyView" anywhere in the code (AutoOpen, at the end of the InsertColumnBreak routine, etc) you want to run it.

janaboo13
07-15-2011, 01:13 PM
Hi Frosty!

That's what I was leaning toward but wasn't sure how to do that.

Now, I run the macro from a form that calls InsertColumnBreaks macro (using a command button). There are some other things that a user can do to cleanup the document using the same form. When done, the user clicks a Close button and ideally that's when I want the view to return to facing pages. So if that's possible, where should I put the "SetMyView" code?

Here's the code that behind the form:

Dim RemovePages As Boolean
Dim DidColumns As Boolean
Dim SecondRun As Boolean

Private Sub CloseButton_Click()

CleanUp.Hide

End Sub

Private Sub CloseButton_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
End Sub

Private Sub InsertBackCover_Click()
CleanUp.Hide
Application.Run MacroName:="InsertBackCover"
CleanUp.Show

CheckBox10.Value = True
End Sub

Private Sub FixTableBordersButton_Click()

CleanUp.Hide
Application.Run MacroName:="FixTableBorders"
CleanUp.Show

CheckBox4.Value = True

End Sub

Private Sub HelpButton_Click()
CleanUpHelp.Show
End Sub

Private Sub DeleteTableSpacer_Click()
CleanUp.Hide
Call DeleteTableSpacer
CleanUp.Show
CheckBox5.Value = True
End Sub

Private Sub AddColumnBreaks_Click()

'Column Breaks
If DidColumns = True Then
MsgBox "You have already run this procedure."
Else
If RemovePages <> True Then

If ActiveDocument.BuiltInDocumentProperties(wdPropertySubject) = "Russian" Then
GoTo RussianDoc
Else
x = MsgBox("The procedure " & Chr(34) & "Remove Blank Pages/Breaks" & Chr(34) & " removes the column breaks added by this procedure" & Chr(13) & _
"and should be run before this procedure. Would you like to run it now?" & Chr(13) & Chr(13) & _
"Selecting 'Yes' will run both procedures." & Chr(13) & _
"Selecting 'No' will run only this procedure.", vbYesNoCancel)

If x = vbYes Then
CleanUp.Hide
RemovePages = True
Call RemoveBlanks
CheckBox1.Value = True
Call InsertColumnBreaks
DidColumns = True
CleanUp.Show
ElseIf x = vbNo Then
CleanUp.Hide
Call InsertColumnBreaks
DidColumns = True
CleanUp.Show
Else
'Cancel
End If
End If
Else
RussianDoc:
CleanUp.Hide
Call InsertColumnBreaks
DidColumns = True
CleanUp.Show
End If
End If

CheckBox3.Value = True

Call SetMyView
End Sub

Private Sub UpdateAllFields_Click()
CleanUp.Hide
Application.Run MacroName:="UpdateAllFields"
CleanUp.Show
CheckBox9.Value = True
End Sub

Private Sub FixSpaces_Click()
'Don't do for Russian
If ActiveDocument.BuiltInDocumentProperties(wdPropertySubject) = "Russian" Then
MsgBox "This feature is not available for Russian documents."
Else
CleanUp.Hide
Call RemoveSpaces
CleanUp.Show
End If
CheckBox2.Value = True
End Sub

Private Sub RemoveBlankPagesButton_Click()

'Removes blank pages and breaks

'Don't do for Russian
If ActiveDocument.BuiltInDocumentProperties(wdPropertySubject) = "Russian" Then
MsgBox "This feature is not available for Russian documents."
Else
If RemovePages <> True Then
x = MsgBox("This procedure removes blank pages, as well as extra column breaks." & Chr(13) & Chr(13) & _
"Do you wish to run this procedure?", vbYesNo)
If x = vbYes Then
CleanUp.Hide
RemovePages = True
Call RemoveBlanks
CleanUp.Show
Else
'Do nothing
End If
Else
MsgBox "You have already run this procedure."
End If
End If

CheckBox1.Value = True
End Sub


I hope this makes sense. Please let me know if you need something else, ok?

Thanks, again! Jan