Peter
Peter

Reputation: 33

Get shape index in powerpoint VBA

I hope this is a super simple question but for some reason i cant figure it out.

I need to delete a subset of the selected shapes on a powerpoint slide using VBA. I can do this using:

ActivePresentation.Slides(1).Shapes.Range(_Index_).Delete

Where _Index_ is either an array of shape indexes (integers) or shape names (stings).

Since the shape names are not unique (and people i am making this macro for have a nasty habit of having multiple shapes with the same name) i need to rely on the shape index number. My problem is i dont know how to get the index number of a given shape.

I can only see how i get the shape name or shape ID using:

ActiveWindow.Selection.ShapeRange(IdNum).Name
ActiveWindow.Selection.ShapeRange(IdNum).ID

So my question is: How do i get the shape index of selected shapes?

Upvotes: 3

Views: 9482

Answers (2)

Steve Rindsberg
Steve Rindsberg

Reputation: 14810

When you group a selection of shapes, the group becomes a new shape appended to the end of the previous z-order position. All of the individual shapes within the group are appended to the z-order after the group shape itself.

I can't find a way of determining which individual item within a group is selected (sub-selected, I guess we should say, since the original parent group remains selected and that's what PPT returns when you query ActiveWindow.Selection.ShapeRange(1).

To identify the currently subselected item within a group, you can use this as a starting point:

Sub WorkWithSubSelectedShapes()
' Do stuff with sub-selected shapes within a group
' Courtesy of Andy Pope

    Dim oSh As Shape
    Dim oGSh As Shape
    Dim x As Long

    Set oSh = ActiveWindow.Selection.ShapeRange(1)

    ' Do something with each shape in the group:
    For Each oGSh In oSh.GroupItems
        Debug.Print oGSh.TextFrame.TextRange.Text
    Next

    ' Now do something with each SUB-SELECTED
    ' shape within the group
    With ActiveWindow.Selection.ChildShapeRange
        For x = 1 To .Count
            Debug.Print .Item(x).Name
            Debug.Print .Item(x).TextFrame.TextRange.Text
        Next
    End With

End Sub

Here's some code that may help generally in processing shapes/groups. It takes account of the fact that there might be groups within groups (within groups (within groups)) ...

Sub ProcessShapes()

    Dim oSh As Shape

    For Each oSh In ActivePresentation.Slides(1).Shapes
        If oSh.Type = msoGroup Then
            Debug.Print "GROUP" & vbTab & oSh.Name & vbTab & oSh.ZOrderPosition

            Call DealWithGroup(oSh)
        Else
            Debug.Print oSh.Name & vbTab & oSh.ZOrderPosition
        End If
    Next

End Sub

Sub DealWithGroup(oSh As Shape)
    Dim x As Long
    For x = 1 To oSh.GroupItems.Count
        If oSh.GroupItems(x).Type = msoGroup Then
            Call DealWithGroup(oSh.GroupItems(x))
        Else
            Debug.Print "GROUP ITEM" & vbTab & oSh.GroupItems(x).Name & vbTab & oSh.GroupItems(x).ZOrderPosition
        End If
    Next
End Sub

And to answer Peter's further (excellent) question, this should work:

Sub TestIndexOf()
    MsgBox IndexOf(ActiveWindow.Selection.ShapeRange(1))
End Sub

Function IndexOf(oSh As Shape) As Long

    Dim x As Long

    With ActiveWindow.Selection.SlideRange.Shapes
        For x = 1 To .Count
            If .Item(x).Name = oSh.Name Then
                ' Found it, report it
                IndexOf = x
            End If
        Next
    End With
End Function

Upvotes: 4

Ahmed AU
Ahmed AU

Reputation: 2777

Try the few lines of code and yow will get names of all the shapes in immediate window (Cttl+G to view Immediate window)

Dim shp As Shape, I As Integer
For Each shp In ActivePresentation.Slides(1).Shapes
I = I + 1
Debug.Print "Index=" & I & " Name= " & shp.Name & " ID= " & shp.Id & " Type= " & shp.Type
Next

Upvotes: 1

Related Questions