1

I have a group of groups of shapes, the relevant ones of which are pairs made of a shape and a text box (the whole drawing is imported as SVG image and ungrouped to make it editable). I would like, for each of the pairs, the shapes to be renamed after what's written in the text boxes, but I cannot find a way to access such shapes. I get the error objects does not support property or method at "Target" and I have tried several ways to name it (oSh(G).GroupItems(i) among others) but non is the correct way, could someone please help me? enter image description here

Sub GiveNamesToShapes()
Dim oSlide As slide
Dim oSh As Shape
Dim i As Integer
Dim Source As String
Dim Target As Shape
Dim Group As Shape
Dim G As Integer


    For Each oSh In ActivePresentation.Slides(1).Shapes
        For G = 1 To ActivePresentation.Slides(1).Shapes.Count
            If ActivePresentation.Slides(1).Shapes(G).Type = msoGroup Then
    
                For i = 1 To oSh.GroupItems.Count
    
                    If oSh.GroupItems(i).TextFrame2.HasText = True Then
    
                    Source = oSh.GroupItems(i).TextFrame2.TextRange
                        
                    ElseIf oSh.GroupItems(i).TextFrame2.HasText = False Then
                    
                        With ActivePresentation.Slides(1).Shapes.Range.GroupItems
                        Target = oSh.GroupItems(i) ''here the error
                        End With
                        
                    End If
    
                    With oSh.GroupItems(i) = Target
                          Set .Name = Source
                    End With
                Next
            End If
        Next
    Next
End Sub

Oran G. Utan
  • 455
  • 1
  • 2
  • 10

1 Answers1

2

This is significantly more difficult than expected because you can not directly access subgroups of groups of shapes with VBA.

This solution uses recursion and accesses the subgroups by ungrouping the "parent" group and then regrouping it.

Sub GiveNamesToShapes()
    Dim oSlide As Slide
    Set oSlide = ActivePresentation.Slides(1)
    
    Dim shp As Shape
    For Each shp In oSlide.Shapes
        If shp.Type = msoGroup Then
            NameGroup shp
        End If
    Next shp
End Sub

Function NameGroup(ByVal oShpGroup As Object) As Long
    Dim groupName As String, shp As Shape, shpRng As ShapeRange, txt As String
    groupName = oShpGroup.Name
    Dim oSlide As Slide: Set oSlide = oShpGroup.Parent
    'Ungroup the group and look at each shape inside the group
    Set shpRng = oShpGroup.Ungroup
    For Each shp In shpRng
        If Not shp.Type = msoGroup Then
            If shp.TextFrame.HasText = msoTrue Then _
                txt = shp.TextFrame.TextRange.Text
        End If
    Next shp
    For Each shp In shpRng
        If Not shp.Type = msoGroup Then
            If shp.TextFrame.HasText = msoTrue Then
                'You can name the TextBox here if desired
                'item.name =
            Else
                'The item that is grouped with the TextBox,
                'except for the TextBox itself, will be named here:
                shp.Name = txt
            End If
        End If
    Next shp
    
    'We need to get the shape ids to group the shpRng again
    Dim ids() As Long, i As Long: ReDim ids(1 To shpRng.Count): i = 1
    For Each shp In shpRng
        If shp.Type = msoGroup Then
            'For shapes that are groups themselves, call the funct. recursively.
            'Because NameGroup dis- and then reassembles the group, shpRng.Group
            'won't work anymore after this. That's why we need to get the ids.
            'NameGroup returns the id of the reassembled group.
            ids(i) = NameGroup(shp): i = i + 1
        Else
            ids(i) = shp.id: i = i + 1
        End If
    Next shp
    
    'Get the indices of the shapes with the ids in the 'ids' array
    Dim indices() As Long, j As Long: ReDim indices(LBound(ids) To UBound(ids))
    For i = LBound(ids) To UBound(ids)
        For j = 1 To oSlide.Shapes.Count
            If oSlide.Shapes(j).id = ids(i) Then indices(i) = j: Exit For
        Next j
    Next i
    Set shp = oSlide.Shapes.Range(indices).Group
    'You can name the group here if desired. By default, it will get its
    'original name back
    shp.Name = groupName
    NameGroup = shp.id 'Return the id of the reassembled group
End Function
GWD
  • 3,081
  • 14
  • 30
  • Thank you, It's giving the right name to the textbox instead of the shape though. – Oran G. Utan Nov 06 '22 at 20:55
  • Oh, i thought thats what you wanted. I just adjusted my code, could you try again? – GWD Nov 06 '22 at 20:56
  • It's naming the group, which is a good thing to keep, but the name should go to the other shape in the pair: there is a group made of two things, one text and one shape, the latter should get the name from the textbox i.e. the one that `item.TextFrame.HasText = msoFalse ` – Oran G. Utan Nov 06 '22 at 21:03
  • I just edited the code again. Now there are three lines naming shapes/groups. The last line is what you seem to want, so you can comment the other lines out as you wish. – GWD Nov 06 '22 at 21:10
  • Great! I tried meanwhile but it was hard to get things right, you were super fast... Thank you. – Oran G. Utan Nov 06 '22 at 21:12
  • I have just noticed that all shapes get the same name, like the first one grabbed becomes the name of all shapes. – Oran G. Utan Nov 06 '22 at 21:13
  • Yes, is that not desired? As i said, i put comments in the lines where the shapes get named, you can edit these lines as you wish. – GWD Nov 06 '22 at 21:14
  • I meant, for each of the pairs, each shape gets the name of the text box, but inside each subgroup, so in each pair, each shape has a different name – Oran G. Utan Nov 06 '22 at 21:15
  • I edited my code again, try if it is now as you expected – GWD Nov 06 '22 at 21:18
  • I added a picture, maybe it explains better – Oran G. Utan Nov 06 '22 at 21:21
  • Oh yes the picture helps, the problem is that you have nested groups, I'll adjust my code in a moment – GWD Nov 06 '22 at 21:28
  • They are still taking all the same name, from the textbox grouped with the circle at the top z-index. – Oran G. Utan Nov 06 '22 at 21:29
  • @Bradipo this is surprisingly difficult because PowerPoint doesn't make it possible to access sub groups of groups in vba unless the parent group is ungrouped first. So we can solve it by letting the macro first determine the group structure by ungrouping all the groups and then regrouping the groups. I'll quickly implement it and will update my answer accordingly – GWD Nov 06 '22 at 21:59
  • yes, I had been reading for weeks for this, I understood one could grab the deepest level items and I thought that would be enough. I was basing my code on this https://stackoverflow.com/questions/53242865/get-shape-index-in-powerpoint-vba, but with this in mind as well https://stackoverflow.com/questions/67809460/access-shape-group-within-a-group-in-vba, which is beyond my VBA knowledge at the moment. – Oran G. Utan Nov 06 '22 at 22:05
  • This ended up being significantly more difficult than expected. I now updated my answer, please check if it works for you and let me know what you think. – GWD Nov 07 '22 at 00:25
  • 1
    Works perfectly. I tested it on two grouped groups of groups of pairs and it worked, too. Fantastic! – Oran G. Utan Nov 07 '22 at 00:37