In PowerPoint 2007 and using VBA, how can I get the placeholder shape on a Slide Master layout that is the "master" for a placeholder shape on the slide?
I am currently using a loop to compare the position and size of the slide placeholder with the position and shape of each placeholder shape in the slide's layout, but this isn't fool-proof. For example, if the placeholder shape is moved on the slide, its position may no longer match the position of any placeholder shapes in the slide's layout. I could reap开发者_如何学Cply the slide's layout to snap placeholders back into position, but that's not what I want to do.
Something in the object model like Shape.Master
would be ideal but, of course, that doesn't exist.
Seeing as there is still no answer to this here or elsewhere I might as well post my code.
For example, if the placeholder shape is moved on the slide,
Here's what I came up with to handle that:
- store the locations of all shapes
- reset the slide layout
- match slide shapes and master slide shapes
- restore the locations of all shapes.
This is the function that does that and returns a mastershapename - shapename mapping.
private Dictionary<string, string> GetShapeMasters(Powerpoint.Slide s)
{
Dictionary<string, string> shapeMasters = new Dictionary<string, string>();
List<ShapeLocation> shapeLocations = new List<ShapeLocation>();
//store locations
foreach (Powerpoint.Shape sh in s.Shapes)
{
shapeLocations.Add(new ShapeLocation()
{
Name = sh.Name,
Location = new System.Drawing.RectangleF(sh.Left, sh.Top, sh.Width, sh.Height)
});
}
//have powerpoint reset the slide
//ISSUE: this changes the names of placeholders without content.
s.CustomLayout = s.CustomLayout;
//compare slide and master
foreach (Powerpoint.Shape sh in s.Shapes)
{
foreach (Powerpoint.Shape msh in s.CustomLayout.Shapes)
{
if (IsShapeMaster(sh, msh))
{
shapeMasters[msh.Name] = sh.Name;
}
}
}
//restore locations
//TODO: might be replaced by undo
foreach (var shm in shapeLocations)
{
Powerpoint.Shape sh = null;
try
{
sh = s.Shapes[shm.Name];
}
catch
{
//Fails for renamed placeholder shapes.
//Have yet to find a decent way to check if a shape name exists.
}
//placeholders do not need to be restored anyway.
if (sh != null)
{
sh.Left = shm.Location.Left;
sh.Top = shm.Location.Top;
sh.Width = shm.Location.Width;
sh.Height = shm.Location.Height;
}
}
return shapeMasters;
}
With this you can do
Dictionary<string, string> shapeMasters = GetShapeMasters(theSlide);
if(shapeMasters.ContainsKey("KnownPlaceholderName"))
Powerpoint.Shape KnownShape = theSlide[shapeMasters["KnownPlaceholderName"]];
And here is the comparison function that takes two shapes and checks if they are "equal". Could be extended to make it more precise.
private bool IsShapeMaster(Powerpoint.Shape sh, Powerpoint.Shape msh)
{
return
sh.Left == msh.Left
&& sh.Top == msh.Top
&& sh.Width == msh.Width
&& sh.Height == msh.Height
&& sh.Type == msh.Type
&& sh.PlaceholderFormat.Type == msh.PlaceholderFormat.Type;
}
Little class that stores original shape location
class ShapeLocation
{
public string Name;
public System.Drawing.RectangleF Location;
}
This is code from a C# VSTO Add-in but I suppose it is not that different from VB or other PPT automation types.
Here you go Ryan, I believe this is what you're asking for.
Sub GetLayoutShapeDetails()
Dim myPPT As Presentation
Set myPPT = ActivePresentation
Dim mySlide As Slide
Set mySlide = myPPT.Slides(6)
Dim slideShape As Shape
Dim slideLayoutShape As Shape
Set slideShape = mySlide.Shapes(1)
If slideShape.Type = msoPlaceholder Then
Dim placeHolderType As Integer
placeHolderType = slideShape.PlaceholderFormat.Type
Set slideLayoutShape = mySlide.CustomLayout.Shapes.Placeholders(placeHolderType)
Dim modifiedPlaceHolder As String
modifiedPlaceHolder = "Shape Name: " & slideShape.Name & _
", Left: " & slideShape.Left & _
", Width: " & slideShape.Width
Dim originalPlaceHolder As String
originalPlaceHolder = "Shape Name: " & slideLayoutShape.Name & _
", Left: " & slideLayoutShape.Left & _
", Width: " & slideLayoutShape.Width
Debug.Print modifiedPlaceHolder
Debug.Print originalPlaceHolder
End If
End Sub
EDIT: JAN 16, 2010 Based off of further research, there doesn't not appear to be a way in VBA to find a shape's corresponding exact match in its slide's layout.
精彩评论