Reputation: 33
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
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
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