0

Following the excellent answer to my previous question, I am trying to make two groups, one made of shapes and one of textboxes, out of an original group of grouped pairs, each composed of a shape and a textbox. I tried creating two arrays, one for each category, by adapting the code from the answer to the previous question and looking at similar questions I found, like here, however what I came up is not working: the function called by the macro stops at the last step (when I try to group the array i.e. Set GroupedShapes = oSlide.shapes.Range(ShapeArray).Group) with error -2147024809 (80070057)': Shapes(uknown member): Illegal value. Bad type: expected ID array of Variants, Integers, Longs, or Strings. I tried leaving blank brackets --> Set GroupedShapes = oSlide.shapes.Range(ShapeArray()).Group as from what I understand something is missing in there, but I get the same error, nor does ...Range(ShapeArray(1 to .shpRng))... work as I receive the prompt I should separate values by a comma. However, I am not even sure that if this is fixed the rest will actually work. Could someone please advise?

Sub GiveNamesToShapes()
    Dim oSlide As slide
    Set oSlide = ActivePresentation.Slides(ActiveWindow.View.slide.SlideIndex)
    
    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

    Dim TextArray() As Variant 'these are the variables I created
    Dim ShapeArray() As Variant
    Dim GroupedShapes As Shape
    Dim GroupedText As Shape
    
    Dim i As Integer 'these are the variables I created
    Dim y As Integer
    
    Dim Shp_Cntr As Double
    Dim Shp_Mid As Double
    
    Dim ShapeLeft As Double
    Dim ShapeRight As Double
    Dim ShapeWidth As Double
    Dim ShapHeight As Double
    
    groupName = oShpGroup.name
    
    Dim oSlide As slide: Set oSlide = oShpGroup.Parent

    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 = msoFalse Then
                        
                With shp
'here is the first array i created (shapes)
                    Dim indicesShapes() As Long, z As Long: ReDim indicesShapes(LBound(ShapeArray) To UBound(ShapeArray))
                        For i = LBound(ShapeArray) To UBound(ShapeArray)
                            For z = 1 To oSlide.shapes.Count
                                Set oSlide.shapes(z) = ShapeArray(i) 'Then indices(i) = j: Exit For
                            Next z
                        Next i

'up to here
                End With
                
                ShapeLeft = shp.Left
                ShapeTop = shp.Top
                ShapeWidth = shp.Width
                ShapeHeight = shp.Height
                
                Shp_Cntr = ShapeLeft + ShapeWidth / 2
                Shp_Mid = ShapeTop + ShapeHeight / 2
                
                shp.name = txt
                
            Else
                With shp
'this is the second Array (for textboxes)
                    Dim indicesText() As Long, p As Long: ReDim indicesText(LBound(TextArray) To UBound(TextArray))
                        For y = LBound(TextArray) To UBound(TextArray)
                            For p = 1 To oSlide.shapes.Count
                                Set oSlide.shapes(p) = TextArray(y) 'Then indices(i) = j: Exit For
                            Next p
                        Next y

'up to here

                .TextFrame.WordWrap = False
                .TextFrame.AutoSize = ppAutoSizeShapeToFitText
                .TextFrame.TextRange.ParagraphFormat.Alignment = ppAlignCenter
                .TextFrame.VerticalAnchor = msoAnchorMiddle
                
                .Left = Shp_Cntr - .Width / 2
                .Top = Shp_Mid - Height / 2
                    
                End With
            End If
        End If
    Next shp
    
'here is where I try to group the items in the arrays and I get the error
    Set GroupedShapes = oSlide.shapes.Range(ShapeArray).Group
    Set GroupedText = oSlide.shapes.Range(TextArray).Group
    
End Function

EDIT: I have just tried the below, but I get Type mismatch

    Set GroupedShapes = oSlide.shapes.Range(indicesShapes(ShapeArray)).Group
    Set GroupedText = oSlide.shapes.Range(indicesText(TextArray)).Group

EDIT2:

I went back to the answer I am referring to and realized I did not add the loop to ungroup to the "core", that is till there are no groups left. I then changed the order of the arrays and placed them after this, naively thinking that by doubling the variables for shapes and textboxes I would get the expected result, but the first pair of shapes only gets ungrouped. The idea I had was to get the ids of shapes and textboxes, so they would be grouped accordingly, however the below stops at the first pair despite the loop I have added until there are groups so the last line Set GroupedText = oSlide.shapes.Range(indicesText).Group gives error saying that in the shape range there must be at least two objects.

Sub GiveNamesToShapes()
    Dim oSlide As slide
    Set oSlide = ActivePresentation.Slides(ActiveWindow.View.slide.SlideIndex)
    
    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
    Dim TextArray() As Variant
    Dim ShapeArray() As Variant
    Dim GroupedShapes As Shape
    Dim GroupedText As Shape
   
    groupName = oShpGroup.name
    
    Dim oSlide As slide: Set oSlide = oShpGroup.Parent

    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 = msoFalse Then

                
                shp.name = txt
                

            End If
        End If
    Next shp
    
    
    Dim Shapeids() As Long, i As Long: ReDim Shapeids(1 To shpRng.Count): i = 1
    Dim Textids() As Long, y As Long: ReDim Textids(1 To shpRng.Count): y = 1
    For Each shp In shpRng
            Do While shp.Type = msoGroup  'I added this loop to ungroup recursively, but it does not go through all groups, it works only on the first one               
                            Call NameGroup(shp)
            Loop
            
            If shp.TextFrame.HasText = msoTrue Then
        
                    Textids(y) = shp.id: y = y + 1
            
            ElseIf shp.TextFrame.HasText = msoFalse Then
            
                    Shapeids(i) = shp.id: i = i + 1
            End If
    Next shp
    
    
    Dim Textindices() As Long, p As Long: ReDim Textindices(LBound(Textids) To UBound(Textids))
        For y = LBound(Textids) To UBound(Textids)
            For p = 1 To oSlide.shapes.Count
                If oSlide.shapes(p).id = Textids(y) Then Textindices(y) = p: Exit For
            Next p
        Next y
        
    Dim Shapeindices() As Long, z As Long: ReDim Shapeindices(LBound(Shapeids) To UBound(Shapeids))
        For i = LBound(Shapeids) To UBound(Shapeids)
            For z = 1 To oSlide.shapes.Count
                If oSlide.shapes(z).id = Shapeids(i) Then Shapeindices(i) = z: Exit For
            Next z
        Next i
    
    
    Set GroupedShapes = oSlide.shapes.Range(Shapeindices).Group 'here it stops and it says there must be two objects to make a group, only the first pair is ungroupd (the primary, big group containing all is gone) while all oteher pairs are still grouped

    Set GroupedText = oSlide.shapes.Range(Textindices).Group 
    
End Function

As is

enter image description here

Expected Result

enter image description here

Oran G. Utan
  • 455
  • 1
  • 2
  • 10
  • Your latest type mismatch because you've declared GroupedShapes and GroupedText as shapes. But a group is not a shape, it's a ShapeRange. https://learn.microsoft.com/en-us/office/vba/api/word.shaperange – John Korchok Nov 18 '22 at 00:38
  • Thank you, I changed them to ShapeRange, but I got the same error. – Oran G. Utan Nov 18 '22 at 10:42

1 Answers1

0

A colleague of mine always tells me to use F8 to se what macros do, and all the above shows clearly I did not do it. Not enough. I realized I was trying to group the items while in the function, when in fact this should have occurred in the macro itself, after the ungrouping. I took inspiration from this answer (keeping in mind the comment right below it: shapes must have different names) and now everything is working as expected.

One thing I do not understand: at the line Debug.Print Parent.name the Immediate Window says Microsoft Excel, but I am running this in PowerPoint and Excel is closed.

Sub GiveNamesToShapes_Center_AndThenRegroup()
    Dim oSlide As slide
    Set oSlide = ActivePresentation.Slides(ActiveWindow.View.slide.SlideIndex)
    
    Dim x As Long
    Dim sTemp As String
    
    Dim ShapeList() As String
    Dim ShapeCount As Long
    
    Dim TextList() As String
    Dim TextCount As Long
    
    Dim shp As Shape
    For Each shp In oSlide.shapes
        If shp.Type = msoGroup Then
            NameGroup shp
            
        Else
        
        For x = 1 To oSlide.shapes.Count

            If oSlide.shapes(x).TextFrame.HasText = msoFalse Then
                ShapeCount = ShapeCount + 1
                
                
            Else
                TextCount = TextCount + 1
            End If
        Next x 'EDIT 2022/11/24 --> I added 'x' as with crowded groups coming from SVG files the part above ''If shp.Type = msoGroup Then'' was being skipped


        ReDim ShapeList(1 To ShapeCount)
        ReDim TextList(1 To TextCount)

        ShapeCount = 0
        TextCount = 0

        For x = 1 To oSlide.shapes.Count

            If oSlide.shapes(x).TextFrame.HasText = msoFalse Then
                ShapeCount = ShapeCount + 1
                ShapeList(ShapeCount) = oSlide.shapes(x).name
                
            Else
                TextCount = TextCount + 1
                TextList(TextCount) = oSlide.shapes(x).name
            End If
        Next x 'EDIT 2022/11/24 --> I added 'x' as with crowded groups coming from SVG files the part above ''If shp.Type = msoGroup Then'' was being skipped


        If UBound(ShapeList) > 0 Then
            oSlide.shapes.Range(ShapeList).Group
        End If
        If UBound(TextList) > 0 Then
            oSlide.shapes.Range(TextList).Group
        End If
            

        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
    

    
    Dim Shp_Cntr As Double
    Dim Shp_Mid As Double
    
    Dim ShapeLeft As Double
    Dim ShapeTop As Double
    Dim ShapeWidth As Double
    Dim ShapeHeight As Double
    
    
    groupName = oShpGroup.name
    Debug.Print oShpGroup.name
    Dim oSlide As slide: Set oSlide = oShpGroup.Parent
    Debug.Print Parent.name

    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 = msoFalse Then
            
                shp.name = txt
            
                ShapeLeft = shp.Left

                ShapeTop = shp.Top

                ShapeWidth = shp.Width

                ShapeHeight = shp.Height

                
                Shp_Cntr = ShapeLeft + ShapeWidth / 2
                Shp_Mid = ShapeTop + ShapeHeight / 2

            Else

                With shp
                                shp.name = "Textbox " & txt
                    .TextFrame.WordWrap = False
                    .TextFrame.AutoSize = ppAutoSizeShapeToFitText
                    .TextFrame.TextRange.ParagraphFormat.Alignment = ppAlignCenter
                    .TextFrame.VerticalAnchor = msoAnchorMiddle
                    
                    .Left = Shp_Cntr - (.Width / 2)
                    .Top = Shp_Mid - (.Height / 2)
                End With


            End If
        End If
    Next shp
    

    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

             NameGroup shp

        End If
    Next shp

End Function



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