Get shape index in powerpoint VBA - 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?

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

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

Related

Listing the selected slide index numbers

I have a large presentation and I'm looking to select a number of slides positioned a different positions and receive a list of the slide index numbers. My idea is for this list to appear in a message box.
So far I have put together the below which gives me each slide number in different message boxes. I'm looking for a list to appear in 1 message box that I can copy and paste into an email.
Ideally I'd like to add some extra text to the message box so I can copy and paste to a pre made email. I can probably take that part on though.
Any help would be greatly received.
Sub ShowMeSlideNumbers()
Dim oSld As Slide
For Each oSld In ActiveWindow.Selection.SlideRange
MsgBox "The slide index of the current slide is:" & oSld.SlideIndex
Next oSld
Exit Sub
End Sub
You can do this by creating an array to store the selected index numbers. Then read the array numbers back in reverse order to create a string. Finally, display that string as part of a MsgBox:
Sub ShowMeSlideNumbers()
Dim oSld As Slide
Dim X As Integer, Y As Integer, arrSlideNumbers() As Integer
Dim strSlideNumbers As String
X = 0
For Each oSld In ActiveWindow.Selection.SlideRange
ReDim Preserve arrSlideNumbers(X)
arrSlideNumbers(X) = oSld.SlideIndex
X = X + 1
Next oSld
For Y = UBound(arrSlideNumbers) To 2 Step -1
strSlideNumbers = strSlideNumbers & CStr(arrSlideNumbers(Y)) & ", "
Next Y
strSlideNumbers = strSlideNumbers & CStr(arrSlideNumbers(1)) & " and "
strSlideNumbers = strSlideNumbers & CStr(arrSlideNumbers(0))
MsgBox "The slide indices of the selected slides are: " & strSlideNumbers & "."
End Sub
A simple mod of your existing code should do it:
Sub ShowMeSlideNumbers()
Dim oSld As Slide
Dim sTemp as string
For Each oSld In ActiveWindow.Selection.SlideRange
sTemp = sTemp & "The slide index of the current slide is:" & oSld.SlideIndex & VbCRLF
Next oSld
MsgBox sTemp
End Sub

Export Only Slides Within a Certain Section in Powerpoint VBA

I have code that exports slides to PNG files if they meet certain criteria (i.e. have a certain named shape in the slide). There will be occassions where slides will not have any known shape names, but they will be within a named "section".
I know I must somehow use the ActivePresentation.SectionProperties, but I am not sure how to go about doing this. I've tried things along the line of the below code with no success. In this example the name of the section is "Test". There will be many different sections and I would need to do this for several of those sections. Any help would be much appreciated. Thank you!
Dim sld As Slide
i = 1
For Each sld in ActivePresentation.Slides
If ActivePresentation.SectionProperties.Name("Test") Then
ActivePresentation.Slides(i).Export filenamepng & "TEST" & i & ".png", "PNG"
End If
i = i + 1
Next
#Hunter21188
I guess this is what you need.
You will check of which section every slide belongs.
After this you verify if it's from "Test" section, if is true gotcha! Export.
Obs. The function convert SectionIndex, from Slide Atribute to SectionName, that is not in Slides collection.
Sub Test_Export()
Dim sld As Slide
i = 1
DesiredSection = SectionIndexOf("Test")
For Each sld In ActivePresentation.Slides
If sld.sectionIndex = DesiredSection Then
ActivePresentation.Slides(i).Export filenamepng & "TEST" & i & ".png", "PNG"
End If
i = i + 1
Next
End Sub
Function SectionIndexOf(sSectionName As String) As Long
Dim x As Long
With ActivePresentation.SectionProperties
For x = 1 To .Count
If .Name(x) = sSectionName Then
SectionIndexOf = x
End If
Next
End With
End Function

VBA For each - loop order

In VBA, it's possible to loop through shapes. For example:
For Each shp In slide.Shapes
shp.top=0
Next
The question is, which parameter is being used to determine the order of the loop and how can this parameter be set?
edited after OP's clarification about his need of looping through shapes from the highest on the lowest
you can use SortedList object use Shape Top property as the SortedList key and the Shape object itself as its corresponding value:
Sub Main()
Dim shp As Shape
Dim j As Long
With CreateObject("System.Collections.SortedList")
For Each shp In slide.Shapes
.Add shp.Top, shp
Next
For j = 0 To .Count - 1 'list shapes from the highest to the lowest
MsgBox .GetByIndex(j).Name & " - " & .getkey(j)
Next
End With
End Sub
I found the answer on the MicroSoft site:
Shape.ZOrderPosition Property (PowerPoint)
The site says "A shape's position in the z-order corresponds to the shape's index number in the Shapes collection.".
I then did a short sort routine to set the z-order position based on the .top parameter of the shape:
For i = 2 To sld.Shapes.Count
If sld.Shapes(i).Top < sld.Shapes(i - 1).Top _
and sld.Shapes(i).ZOrderPosition > sld.Shapes(i - 1).ZOrderPosition Then_
sld.Shapes(i).ZOrder msoSendBackward
Next i

Access a Shape inside another one in VBA

I have big shapes on my worksheet (a group of shapes), and inside everyone of them others little shapes (the blue rectangles),
I made a for loop for inside each Big shape to fill automatically the little shapes, but how can I loop over the Big ones, because all the big shapes are similars, and they have the same names for the littles shapes inside ?
How can I acces the little shape from the big one ?
I tried this but didn't worked
ActiveSheet.Shapes.Range(gr).Select
ActiveSheet.Shapes.Range(Array(x)).Select
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = Format(Range(y_1).Value, "#,##0") & " k" & Chr(13) & Format(Range(y_2).Value, "#,##0.00") & " DT"
The "gr" variable takes every time the name of the big shapes (Graph_1 .. Graph_5)
and the x variable takes the name of the little shapes inside (rect_1 .. rect_21)
I think this code does not help because my approach it's like how to access a case in an array if I can say ?
For Each myshape In ActiveSheet.Shapes
You can access child shapes inside a group by using following example:
Sub test()
Dim shp As Shape
Dim shpChild As Shape
For Each shp In Sheet1.Shapes
If shp.Type = msoGroup Then
'/ Found a group. List all the child shapes here.
For Each shpChild In shp.GroupItems
Debug.Print "Child name :" & shpChild.Name & " Group name : " & shp.Name
Next
Else
'/ No group. Individual shape.
Debug.Print shp.Name
End If
Next
End Sub
Here... you should have figured it out yourself :)
Sub test()
Dim shp As Shape
Dim shpChild As Shape
For Each shp In Sheet1.Shapes
If shp.Type = msoGroup And shp.Name = "A" Then
'/ Found a group called "A". List all the child shapes here.
For Each shpChild In shp.GroupItems
If shpChild.Name = "X" Then
'/ Found X.
shpChild.TextFrame2.TextRange.Text = "Hello from VBA!!!"
End If
Next
Else
'/ No group. Individual shape.
Debug.Print shp.Name
End If
Next
End Sub

Difficulties in iterating through ppt group member (vba absolute beginner)

Thanks Doug :-)
I need an idea for a non-programmer how to achieve iterating through groups.
I started with SO which works fine as long as I only take the .Names of the shapes.
But I need to try to check the type of every item in the group too
I have a whole subset of questions to the shape (Sub CheckTextConformity)
This is the code as it runs - but ignores Groups. I started with the idea to call A subroutine for groups - but then what if the Group contains groups too etc.?
From Sub CheckAndReportOhneGroups() I call Sub WhatTypes... and depending on the type I call CheckTextConformity to give me information about the shape (especially text info).
To deal with groups (and possibly groups within groups) use something like this:
Sub Example()
Dim oSh As Shape
Dim oSl As Slide
For Each oSl In ActivePresentation.Slides
For Each oSh In oSl.Shapes
If oSh.Type = msoGroup Then
'Debug.Print "GROUP"
Call DealWithGroups(oSh)
Else
Debug.Print oSh.Name & vbTab & oSh.Type
End If
Next
Next
End Sub
Sub DealWithGroups(oSh As Shape)
Dim x As Long
Debug.Print "GROUP"
For x = 1 To oSh.GroupItems.Count
If oSh.GroupItems(x).Type = msoGroup Then
Call DealWithGroups(oSh.GroupItems(x))
Else
Debug.Print vbTab & oSh.GroupItems(x).Name & vbTab & oSh.GroupItems(x).Type
End If
Next
End Sub
Yes. The snake is eating its own tail. ;-)