Handling a Shape by its Placeholder Name in PowerPoint Handling a Shape by its Placeholder Name in PowerPoint vba vba

Handling a Shape by its Placeholder Name in PowerPoint


I have a potential solution for you.

The problem is the footer, page number, and date placeholders on the slide master. They are included in the placeholder collection on the slide master, but when an individual slide is created they become their own properties of the slide (under the .HeaderFooter property). This results in a different count of placeholders on the Master and on the slides, and because these placeholders can be in the middle of the collection, the indexes don't align.

So, one possible solution is to remove these three placeholders from your Master, which is done by opening the Slide Master and unchecking the footers checkbox. If you do this, you'll find that the number of placeholders on the Master and on the Slides are the same, and all of the index numbers line up. You still can't use the SlideMaster.CustomLayouts(n).Shapes.Placeholders(m).Name property to access the correct placeholder on the actual slide. However, once you know the index of the placeholder ("m" in my example in the last sentence), you should be able to access the correct placeholder on the slide via SlideObj.Shapes.PlaceHolders(m). You could iterate through your SlideMaster.Shapes.PlaceHolders first and store the index for later use.

If you want footer fields, simply add new Text placeholders to your slide master, put them at the bottom of the slide, and then insert the page number, date, or fixed text into them.

Summary:

  1. Uncheck the Footers checkbox on all slide masters that you care about. Not sure if this can be done programatically.

  2. Iterate through ActivePresentation.SlideMaster.CustomLayout(n).Shapes.Placeholders for each of your Slide Masters (Custom Layouts) looking at the .Name property to find the placeholder(s) you are interested in. Store that in an array (would use name of the placeholder as the array name, so if the placeholder name was "datatable" I would use datatable[n])=index # of the placeholder on the CustomLayout/Master. Do this once and store it in a global variable.

  3. When you want to access the placeholder on a slide, get the SlideMaster index for the slide with SM_index=SlideObj.CustomFormat.Index. Then access the placeholder "datatable" using SlideObj.Shapes.Placeholders(datatable[SM_index])

If you only have a single SlideMaster for all of your slides then you don't need an array and can use a simple variable instead.

If you need actual code, let me know -- but I expect you don't. Let me know if this works in your real world project.


My current workaround is to do the following:

Delcare a module-level Dictionary object, which creates a sort of hash table based on the slide's CustomLayout and the known index of each placeholder within the Slide.Shapes collection. (This I obtain through a simple FOr/Next iteration in a throwaway subroutine).

Since I am building slides from template, I think this is relatively safe and reliable, but not flexible (the whole point of working with POTX template files should be ease of use and flexibility...).

Dim dictShapes As Object 'Dictionary

Then a procedure to establish it based on CustomLayout

Sub SetShapeDict(cLayout as Object)    Set dictShapes = CreateObject("Scripting.Dictionary")    Select Case cLayout.Name        Case "layout_one"            dictShapes("chart RIGHT") = 1            dictShapes("chart RIGHT title") = 2            dictShapes("chart LEFT") = 5            dictShapes("chart LEFT title") = 6        Case "layout_two"            dictShapes("chart RIGHT") = 1            dictShapes("chart RIGHT title") = 2            dictShapes("q text") = 4            dictShapes("source text") = 5      End Select End Sub

I call this function like:

Dim shp as Object 'PowerPoint.ShapeSet shp = GetShapeByIndex(shp.Parent, dictShapes("chart RIGHT"))

The dictionary is initialized in such a manner that I can pass a string argument and it will return the index of the shape, which all should work.

Function GetShapeByIndex(chartSlide As Object, i As Long) As Object    Dim ret    Dim s As Long    'if slide #1, there is no  "Slide Number Placeholder"    ' this placeholder appears in the shapes' 3rd index for    ' both Vertical Master no Background AND Horizontal Master    If chartSlide.SlideNumber = 1 Then        If i > 2 Then            s = i - 1        Else            s = i        End If    Else        s = i    End If    On Error Resume Next    Set ret = chartSlide.Shapes(s)    If Err.Number <> 0 Then Set ret = Nothing    On Error GoTo 0    Set GetShapeByIndex = retEnd Function


I have another workaround. I iterate trough all the shapes in the slide and compare them with some shape properties of the shape in the Custom Layout. I took width, height and autoshapetype. If they are exactly the same I have found the corresponding shape in the slide.

     For Each sh In sl.Shapes        With sl.CustomLayout.Shapes("Name of shape in layout")            If sh.Width = .Width And _                sh.Height = .Height And _                sh.AutoShapeType = .AutoShapeType Then                bFound = True                Exit For            End If        End With    Next sh    If bFound Then        'sh is the shape you are looking for    End If