重置在Word文档中插入的文本框的计数器的代码:

huangapple go评论69阅读模式
英文:

Code for resetting the counter for textboxes inserted in the word document

问题

我有一段代码,它将粗体文本从文本框复制到所选表格的第二列。但是,该代码无法按顺序识别文本框,并从文档中首先插入的文本框复制文本,依此类推。当文本框不按顺序插入时,会出现问题。例如,如果文档中插入了文本框2在文本框1之上,那么表格中将首先复制文本框2中的文本。

如何重置所有文本框的顺序,以便始终从第一个文本框复制文本到最后一个?

'此代码将粗体文本从文本框复制并插入到所选表格的第二列
Sub Copy_text_from_textbox_into_table()
    Dim nNumber As Integer
    Dim strText As String
    Dim i As Long
    Dim doc As Document
    Dim tbl As Table
    Dim rng As Range
    Dim shp As Shape
    
    Set doc = ActiveDocument
    Selection.Collapse Direction:=wdCollapseStart
    Set tbl = Selection.Tables(1)
          
    i = 0
               
    With doc
        For Each shp In .Shapes
       
            If shp.Type = msoTextBox Then
                      
            
                Set rng = shp.TextFrame.TextRange
                With rng.Find
                    .Font.Bold = True
                    .Wrap = wdFindStop
                    .Execute
                    strText = rng.Text
                End With
                i = i + 1
                With tbl.Cell(Row:=i + 1, Column:=2).Range
                    .Delete
                    .InsertAfter Text:=strText
                End With
            
            Else
                MsgBox ("There is no textbox.")
            End If
        Next
    End With
End Sub
英文:

I have a code that copies the bold text from textbox to the column 2 of the selected table. However
this code is not identifying the textboxes in a sequential manner and is copying the text from the textbox that was inserted first in the document and so on. This creates problem when the textboxes are not inserted sequentially. For example, if textbox 2 was inserted above textbox 1 in the document then the text from textbox 2 will be copied first in the table.

How can I reset the sequence of all textboxes so that the text is always copied from the first textbox to the last?

'This code copies bold text from the textboxes and insert into the column 2 of the selected table
Sub Copy_text_from_textbox_into_table()
Dim nNumber As Integer
Dim strText As String
Dim i As Long
Dim doc As Document
Dim tbl As Table
Dim rng As Range
Dim shp As Shape

Set doc = ActiveDocument
Selection.Collapse Direction:=wdCollapseStart
Set tbl = Selection.Tables(1)
      
      i = 0
           
With doc
    For Each shp In .Shapes
   
        If shp.Type = msoTextBox Then
                  
        
        Set rng = shp.TextFrame.TextRange
            With rng.Find
                .Font.Bold = True
                .Wrap = wdFindStop
                .Execute
                strText = rng.Text
            End With
            i = i + 1
            With tbl.Cell(Row:=i + 1, Column:=2).Range
                .Delete
                .InsertAfter Text:=strText
            End With
        
        Else
            MsgBox ("There is no textbox.")
                     End If
  Next
End With
End Sub

答案1

得分: 1

你正在处理的问题涉及文本框的锚定位置。这是文档文本流中Shape被管理的位置。如果你查看底层的XML,你可以看到它是如何工作的(但这并不是理解发生的事情的必要条件)。要查看这些锚点,请转到文件/选项/显示,然后在“始终在屏幕上显示这些格式标记”部分激活“对象锚点”。(注意:这些不会打印出来;它们的另一个术语是“非打印字符”)。

一般来说,当用户插入文本框时,它将锚定到所选位置所在的段落。如果随后拖动文本框,锚点将移动,除非它已经明确“锁定”在位置上。当代码插入文本框时,它将锚定到由Anchor参数指定的Range;如果未设置,那么就有点像抽奖。

当Word遍历Shapes集合时,它会按锚点的顺序依次拾取文档中的连续文本,而不管对象可能出现在页面的哪个位置。

解决这个非常复杂的需求的完整解决方案超出了Stack Overflow的范围。以下说明了涉及和如何处理这个问题的基本原理。

一个简单的方法

解决这个问题的一种方法是循环遍历Shapes,将每个对象添加到数组或集合中。检查数组(或集合)中每个对象的垂直/水平位置,相对于页面边距。然后根据这些信息对数组/集合进行排序。最后,遍历已排序的数组/集合,并将内容分配给表格。

这样做的复杂性进一步增加了一个事实,即Shape的位置可以相对于锚点、边距或页面。以下代码展示了按照它们在页面上出现的顺序(从上到下)获取文本框的可能方法。

为了清晰起见,代码省略了将内容写入表格的步骤,但在此步骤插入了注释。

代码

该代码执行了三个For循环。第一个循环遍历文档中的所有Shapes并测试每个是否是文本框。如果是文本框,则将所需的属性写入用户定义的Type,然后将Type分配给数组。出于效率考虑,这样做比在以后的循环中再次引用每个Shape对象要快。

还要注意,在每次迭代之前,Shape明确设置为相对于页面定位,而不是其他位置。这意味着文本框不会随文本在页面上移动。如果需要这样做,需要添加另一层复杂性来确定每个文本框的相对位置,并根据这个位置计算相对于页面的位置。 (或者,可能可以将设置更改回去,但需要测试以确保文本框不会移动。无论如何,这种复杂程度超出了此问题的范围。)

由于我们需要Shape对象(或标识该对象的方法)和其位置信息,因此需要一个多维数组。在代码启动时,元素(文本框)的数量是未知的,因此数组需要在运行时维度。但是,Redim Preserve只能更改最后一个维度,因此不适合此目的。因此,信息不能直接分配给多维数组,这就是为什么首先将其分配给用户定义的Type数组的原因,该数组携带了所有信息。

在为数组分配维度之后,将位置信息与Type数组中的信息一起分配给它,同时填充一个包含索引值和Shape名称的第三个数组。

第三个数组的原因是使用WordBasic.SortArray对数组按页面上ShapesTop位置进行排序。这将所有元素强制转换为相同的数据类型,这意味着不保留Shape.Name的字符串值。

最后,代码循环遍历已排序的数组,该数组现在按照页面上每个文本框的升序顺序排列。

Public Type DocShapes
    shpName As String
    top As Double
    left As Double
End Type

Sub GetTextBoxPositionalOrder()
    Dim doc As Word.Document
    Dim shp As Word.Shape
    Dim aShapes() As Variant
    Dim counter As Long, i As Long
    Dim shpType As DocShapes
    Dim shpTypes() As DocShapes
    Dim shpIndex() As Variant
    
    counter = 0
    Set doc = ActiveDocument
    For Each shp In doc.Shapes
        'Count the shapes to dimension the array and
        'assign to user-defined Type
        If shp.Type = msoTextBox Then
            shp.RelativeVerticalPosition = wdRelativeVerticalPositionPage
            shp.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
            shpType.shpName = shp.Name
            shpType.left = shp.left
            shpType.top = shp.top
            ReDim Preserve shpTypes(counter)
            shpTypes(counter) = shpType
            counter = counter + 1
         End If
    Next
    
    ReDim Preserve aShapes(counter - 1, 2)
    ReDim Preserve shpIndex(counter - 1, 1)
           
    For i = LBound(shpTypes) To UBound(shpTypes)
        shpIndex(i, 0) = i + 1
        shpIndex(i, 1) = shpTypes(i).shpName
        aShapes(i, 2) = i 'corresponds to the index
        aShapes(i, 0) = shpTypes(i).top
        aShapes(i, 1) =

<details>
<summary>英文:</summary>

The issue you&#39;re dealing with is the position in which the textboxes are *anchored*. This is the place in the document&#39;s text flow where the Shape is managed. If you were to look at the underlying XML you could see how this works (but that&#39;s not necessary for understanding what&#39;s happening). In order to see these anchors, go to File/Options/Display and activate &quot;Object anchors&quot; in the section &quot;Always show these formatting marks on the screen&quot;. (Note: these do not print out; another term for them is &quot;non-printing characters&quot;.)

[![enter image description here][1]][1]

Generally, when the user inserts a text box, it will anchor to the paragraph in which the selection is located. If the text box is then dragged, the anchor will move, unless it&#39;s been explicitly &quot;locked&quot; in position. When code inserts a text box, it will anchor to the `Range` specified by the `Anchor` parameter; if that&#39;s not set, it&#39;s a bit of a lottery.

When Word runs through the `Shapes` collection it follows the contiguous text in the document, picking up the `Shapes` in the order of the anchors, no matter where the object might appear on the page.

A complete solution to this very complex requirment goes beyond the scope of Stack Overflow. The following illustrates the basics about what&#39;s involved and how it can be approached. 

**A simple approach**

An approach to solving this would be to loop the `Shapes`, adding each object to an array or collection. Check the vertical / horizontal positions of each object in the array (or collection), relative to the page margins. Then sort the array/collection according to this information. Finally, go through the sorted array/collection and assign the content to the table.

Doing this is further complicated by the fact that `Shape` positions can be relative to the anchor point, to a margin or to a page.

The following code shows a possible approach to getting the text boxes in the correct order (top-to-bottom) as they appear on a page.

For the sake of clarity, the step of writing the content to a table has been left out, but a comment is inserted at the point this would take place.

**The code**

The code performs three `For`loops. The first loops all `Shapes` in the document and tests whether each is a text box. If it is, the required properties are written to a user-defined `Type`, then the `Type` is assigned to an array. This is done for reasons of efficiency: looping an array of a `Type` is faster than addressing each `Shape` object again, in a later loop.

Note also, before each iteration, the `Shape` is explicitly set to be positioned relative to the page, rather than anything else. This means that the text boxes will not move on the page with the text. If this is required, another level of complexity needs to be added to ascertain how each text box is positioned, relatively, and calculate the position relative to the page based on that. (Or, it might be possible to change the setting back, but that would need to be tested to make sure the text boxes do not move. In any case, such a level of complexity goes beyond the scope of this question.) 

Since we need both the `Shape` object (or a way to identify that object) and its positional information, a multi-dimensional array is needed. The number of elements (TextBoxes) is unknown when the code starts, so the array needs to be dimensioned during run-time. But `Redim Preserve` can only change the last dimension, so is not suited to this purpose. Therefore, the information cannot be assigned directly to the multi-dimensional array, which is why it&#39;s first assigned to an array of the user-defined `Type`, which carries all the information.

After dimensioning the array, the positional information is assigned to it from the array of the `Type`, along with an index value. At the same time, a third array, with the index value and the name of the `Shape` is populated.

The reason for the third array is that `WordBasic.SortArray` is used to sort the array by the `Top` position of the `Shapes` on the page. This coerces all elements into the same data type, meaning the string value of the `Shape.Name` is not retained. 

Finally, the code loops the sorted array, which is now in ascending order of each text box on the page.&#167;


    Public Type DocShapes
        shpName As String
        top As Double
        left As Double
    End Type
    
    Sub GetTextBoxPositionalOrder()
        Dim doc As Word.Document
        Dim shp As Word.Shape
        Dim aShapes() As Variant
        Dim counter As Long, i As Long
        Dim shpType As DocShapes
        Dim shpTypes() As DocShapes
        Dim shpIndex() As Variant
        
        counter = 0
        Set doc = ActiveDocument
        For Each shp In doc.Shapes
            &#39;Count the shapes to dimension the array and
            &#39;assign to user-defined Type
            If shp.Type = msoTextBox Then
                shp.RelativeVerticalPosition = wdRelativeVerticalPositionPage
                shp.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
                shpType.shpName = shp.Name
                shpType.left = shp.left
                shpType.top = shp.top
                ReDim Preserve shpTypes(counter)
                shpTypes(counter) = shpType
                counter = counter + 1
             End If
        Next
        
        ReDim Preserve aShapes(counter - 1, 2)
        ReDim Preserve shpIndex(counter - 1, 1)
               
        For i = LBound(shpTypes) To UBound(shpTypes)
            shpIndex(i, 0) = i + 1
            shpIndex(i, 1) = shpTypes(i).shpName
            aShapes(i, 2) = i &#39;corresponds to the index
            aShapes(i, 0) = shpTypes(i).top
            aShapes(i, 1) = shpTypes(i).left
        Next
        WordBasic.SortArray aShapes, 0, 0, UBound(aShapes), 0, 0
        For i = LBound(aShapes) To UBound(aShapes)
    &#39;&#39;&#39;Write the text box content to the table at this point
            Debug.Print shpIndex(aShapes(i, 2), 1), aShapes(i, 0), aShapes(i, 1)
        Next
    End Sub

&#167; Note that this code works for a one-page document. If you need to handle text boxes on multiple pages, then an added dimension is required: on which page each `Shape` is located. Then the text box information would first need to be sorted by page, and then by position on each page. Or set it up to work with one page&#39;s `Shapes` at a time.

It would also be possible to use a different sort algorithm - there are a lot out there. I used `WordBasic.SortArray` because 1) it&#39;s built-in and 2) I couldn&#39;t take the time to research various sort algorithms.


  [1]: https://i.stack.imgur.com/Shw41.png




</details>



huangapple
  • 本文由 发表于 2020年1月4日 02:01:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/59583235.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定