Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

In the process of generating a slide via VBA in powerpoint, I need to insert a "Wingdings symbol" within a generated text which is a comparison of two values. I made this method which is working exactly as I want

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

The formatDifference Sub is basically just adding a bullet point line in the text (in the example below, the procedure is called 4 times before I add a non-bullet text).

What I don't understand is when I initiate the text with some text and then use the InsertSymbol method, the text seems to actually get replaced instead of having the symbol appended at the end. Here's an example of the different code :

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

And here's a comparison of the two results I get from the codes above (in the same order) :

Example of the difference the codes make

My understanding of the InsertSymbol method was that it would insert the symbol at the end of the last paragraph, but it does not look like it... Is my second example faulty or did I misunderstand the description of the method?


P.S. Note: the header parameter was holding the carriage return and line feed characters which is why the second capture has all the points on the same line since that first part seems to be replaced.

like image 315
Sirmyself Avatar asked Oct 28 '22 13:10

Sirmyself


1 Answers

Documentation of InsertSymbol implementations

Microsoft Word's Range.InsertSymbol and Selection.InsertSymbol implementations are described as:

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's TextRange.InsertSymbol implementation is described as:

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.

And then there are Office TextRange2.InsertSymbol and PowerPoint TextRange2.InsertSymbol methods described as:

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

With this in mind, the PowerPoint documentation of the TextRange.InsertSymbol implementation is a bit inaccurate including a wrong explanation ("after the first sentence") of the included code example.

InsertSymbol after TextRange

If you want to get the symbol inserted after the provided TextRange, I suggest following wrapper function:

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

It distinguishes two cases:

  • If the last character is a vbCR (Chr(13), carriage return, CR), the symbol is added before the CR (the CR is replaced by the new symbol and added afterwards again).
  • In all other cases, an arbitrary character is added first and then replaced by the new symbol.

Test

The function can be tested for whole textframes, paragraphs or characters by this:

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
like image 107
Asger Avatar answered Nov 15 '22 05:11

Asger