为什么 TextRange.InsertSymbol 方法会替换我的 TextRange 中的文本?

Why does the TextRange.InsertSymbol method replace the text in my TextRange?

在通过 VBA 在 powerpoint 中生成幻灯片的过程中,我需要在生成的文本中插入一个 "Wingdings symbol",这是两个值的比较。我做了这个方法,它完全按照我想要的方式工作

Sub formatDifference(header As String, old As Integer, now As Integer, txt As TextRange)
    Dim diff As Integer
    diff = old - now

    With txt
        If (diff > 0) Then
            .InsertSymbol "Wingdings", getArrowCharCode("down")
                                       ' getArrowCharCode is a custom function to get the 
                                       ' char code as an Integer
        ElseIf (diff = 0) Then
            .InsertSymbol "Wingdings", getArrowCharCode("right")
        Else
            .InsertSymbol "Wingdings", getArrowCharCode("up")
        End If

        .InsertBefore header & now & " ("    ' <-- note this line
        .InsertAfter " " & Abs(diff) & ")"
    End With
End Sub

formatDifference Sub 基本上只是在文本中添加项目符号行(在下面的示例中,在我添加 non-bullet 文本之前调用了 4 次过程)。

我不明白的是,当我用一些文本启动文本然后使用 InsertSymbol 方法时,文本似乎实际上被替换了,而不是在末尾附加了符号。这是不同代码的示例:

Sub formatDifference(header As String, old As Integer, now As Integer, txt As TextRange)
    Dim diff As Integer
    diff = old - now

    With txt
        .InsertAfter header & now & " (" ' <-- line moved here
                                         '     it doesn't matter if I use 
                                         '     .Text = "initial text"', 
                                         '     it will do the same thing
        If (diff > 0) Then
            .InsertSymbol "Wingdings", getArrowCharCode("down")
        ElseIf (diff = 0) Then
            .InsertSymbol "Wingdings", getArrowCharCode("right")
        Else
            .InsertSymbol "Wingdings", getArrowCharCode("up")
        End If
        .InsertAfter " " & Abs(diff) & ")"
    End With
End Sub

下面是我从上面的代码中得到的两个结果的比较(顺序相同):

我对InsertSymbol方法的理解是它会在最后一段的末尾插入符号,但看起来不像......我的第二个例子有问题还是我误解了description of the method?


P.S。注意:header 参数包含回车符 return 和换行符,这就是为什么第二次捕获的所有点都在同一行上,因为第一部分似乎已被替换。

我可以制定一个似乎工作正常的解决方法。

Sub AppendSymbol(ByRef orig As TextRange, ByVal fontName As String, ByVal charCode As Integer, Optional ByVal position As Integer = -1)
    Dim strStart, strEnd As String

    If ((position < 0) Or (position >= Len(orig.text))) Then
        orig.Paragraphs(orig.Paragraphs.Count + 1).InsertSymbol fontName, charCode
        'this one just inserts the symbol at the end by forcing a new paragraph
    Else
        strStart = Left(orig.text, position)
        strEnd = Right(orig.text, Len(orig.text) - position)

        orig.Paragraphs(1).InsertSymbol fontName, charCode
        orig.InsertBefore strStart
        orig.InsertAfter strEnd
    End If
End Function

在那个子目录中,我基本上复制了原始行,将其替换为符号,然后 re-append 符号周围的字符串。

我现在可以这样称呼那个 Sub 了:

Private Sub displayTotal(ByRef para As TextRange, ByVal prevCompare As Testing)
    Dim arrowDirection As String
    Dim tempDifference As Integer

    tempDifference = p_total - prevCompare.Total
    para.InsertAfter "Number of elements : " & p_total & " ("

    'calling the Sub
    AppendSymbol para, "Wingdings", getWingdingArrowChar(getArrowDirection(tempDifference))

    para.InsertAfter " " & Abs(tempDifference) & ")"
    para.IndentLevel = 2
    para.ParagraphFormat.Bullet = msoFalse
End Sub

至于解释,Asger好像说到点子上了。该方法的实现,显然类似于 Word 的,需要折叠文本范围才能添加符号。

在上面的自定义方法中,orig.Paragraphs(orig.Paragraphs.Count + 1).InsertSymbol fontName, charCode 行基本上是通过在当前段落后面添加一个段落来强制折叠当前段落,这就是 InsertSybol 方法按预期工作的原因。

InsertSymbol 实现的文档

Microsoft Word 的 Range.InsertSymbol and Selection.InsertSymbol 实现被描述为:

Inserts a symbol in place of the specified range.
If you don't want to replace the range, use the Collapse method before you use this method.

Microsoft Publisher 的 TextRange.InsertSymbol 实现被描述为:

Returns a TextRange object that represents a symbol inserted in place of the specified range or selection.
If you do not want to replace the range or selection, use the Collapse method before you use this method.

然后有 Office TextRange2.InsertSymbol and PowerPoint TextRange2.InsertSymbol 方法描述为:

Inserts a symbol from the specified font set into the range of text represented by the TextRange2 object.

考虑到这一点,TextRange.InsertSymbol 实施的 PowerPoint 文档有点不准确,包括错误的 解释( “在第一句之后”)包含的代码示例。

InsertSymbol after TextRange

如果你想在提供的 TextRange 之后插入符号,我建议使用以下包装函数:

Public Function InsertSymbolAfter(newTextRange As PowerPoint.TextRange, _
                           newFontName As String, _
                           newCharNumber As Long, _
                           Optional newUnicode As MsoTriState = msoFalse) As TextRange

    If Right(newTextRange.Text, 1) = vbCr Then
        Set InsertSymbolAfter = newTextRange.Characters(newTextRange.Characters.Count) _
            .InsertSymbol(newFontName, newCharNumber, newUnicode)
        newTextRange.InsertAfter vbCr
    Else
        Set newTextRange = newTextRange.InsertAfter("#")
        Set InsertSymbolAfter = newTextRange _
            .InsertSymbol(newFontName, newCharNumber, newUnicode)
    End If

End Function

区分两种情况:

  • 如果最后一个字符是vbCRChr(13),回车return,CR),则在CR之前添加符号(CR被新符号代替,之后再添加)。
  • 在所有其他情况下,首先添加任意字符,然后用新符号替换。

测试

可以通过以下方式测试整个文本框、段落或字符的功能:

Private Sub testit()
    Const WingDingsLeft As Long = 231
    Const WingDingsRight As Long = 232
    Const WingDingsUp As Long = 233
    Const WingDingsDown As Long = 234
        
    With ActivePresentation.Slides(1).Shapes(1).TextFrame
        InsertSymbolAfter(.TextRange, "Wingdings", WingDingsUp)
        InsertSymbolAfter(.TextRange.Paragraphs(1), "Wingdings", WingDingsDown)
        InsertSymbolAfter(.TextRange.Characters(2, 1), "Wingdings", WingDingsRight)
    End With
End Sub