Home > Enterprise >  Move text using headings
Move text using headings

Time:03-30

First time I write a question on stackoverflow, after more than 5 years using it ! Hopefully I did not miss the answer in another post and that I'll meet the standards expected to ask a question:

I am trying to dynamically move text in a MS-word document based on a user input, using Headings to find what to move and where to move it.

For the sake example let's say my document is organized like this:

Section 1 Section 2 Section 3 Annex 1

With "Section 1", "Section 2", "Section 3" and "Annex" being defined as Headings 1 style.

In each Sections (and annex) you have a mixed batch of text, tables, pictures, etc.

Let's assume users get asked the following question through VBA (triggered either via a button click event or document open event, does not matter - this I know how to do). Depending on their answer, I would like to either

a) do nothing

b) do the following actions:

  • select the entire "Section 1", including Heading and all the text, figures, tables, etc, in it (in other words - until "Section 2" starts)

  • move it between Section 3 and Annex 1 so that the document structure now looks like this: Section 2 Section 3 Section 1 Annex 1

Dim answer as Integer

answer = MsgBox("Do you like cookies?", vbQuestion   vbYesNo   vbDefaultButton2, "The big question")

if answer = vbYes Then

' e.g. do nothing or end sub

else

' move text as described above

I have of course explored / read quite a few posts on the selection.find, selection.move and range.move methods.

I have reached a stage where I manage to find and select the Section I am interested in using the following code;


Dim answer as Integer

answer = MsgBox("Do you like cookies?", vbQuestion   vbYesNo   vbDefaultButton2, "The big question")

if answer = vbYes Then

' e.g. do nothing or end sub

else

    Selection.WholeStory
    Selection.Collapse wdCollapseStart

    Selection.Find.ClearFormatting
    Selection.Find.Style = ActiveDocument.Styles("Heading 1")
    With Selection.Find
        .Text = "Section 1"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = True
    End With
    Selection.Find.Execute
    Selection.Collapse wdCollapseStart

    Dim r1 As Range
    Set r1 = Selection.Range

    ' keep format settings, only change text
    Selection.Find.Text = "Section 2"
    If Selection.Find.Execute Then
        Selection.Collapse wdCollapseStart
    Else
        Selection.WholeStory
        Selection.Collapse wdCollapseEnd
    End If
    Dim r2 As Range
    Set r2 = ActiveDocument.Range(r1.Start, Selection.Start)
    r2.Select

But I struggle to reach the finish line - that to now move this range (or this selection) to another position in the document based on Headings (in this case, to insert this section between "Section 3" and "Annex 1").

Any suggestions?

CodePudding user response:

You are on the right lines but need to avoid using the Selection object. There are rare circumstances when using Selection is unavoidable but this isn't one of them.

Word has a number of hidden predefined bookmarks, one of which returns the full range of a heading level. This is used in the GetHeadingBlock function below.

A Range also has a FormattedText property that can be used instead of the clipboard.

Sub MoveSection()
    Dim moveRange As Range, destRange As Range
    Set moveRange = GetHeadingBlock("Section 1", wdStyleHeading1)
    If Not moveRange Is Nothing Then
        Set destRange = GetHeadingBlock("Section 3", wdStyleHeading1)
        If Not destRange Is Nothing Then
            destRange.Collapse wdCollapseEnd
            destRange.FormattedText = moveRange.FormattedText
            moveRange.Delete
        End If
    End If
End Sub

Public Function GetHeadingBlock(headingText As String, headingStyle As WdBuiltinStyle) As Range
   Dim findRange As Range
   Set findRange = ActiveDocument.Content
   With findRange.Find
      .ClearFormatting
      .Replacement.ClearFormatting
      .Text = headingText
      .Style = headingStyle
      .Replacement.Text = ""
      .Forward = True
      .Format = True
      .Wrap = wdFindStop
      If .Execute Then Set GetHeadingBlock = _
         findRange.GoTo(What:=wdGoToBookmark, Name:="\HeadingLevel")
   End With
End Function
  • Related