在 PowerPoint 中按占位符名称处理形状
Handling a Shape by its Placeholder Name in PowerPoint
我正在尝试创建一个函数,它将 return 一个特定的形状,基于分配给 [=11= 的 已知 名称 属性 ] 目的。我不能使用形状 .Name
因为这是事先不知道的,即使在从 template/layout.
创建幻灯片时也是如此
挑战似乎在于自定义布局如何与实际幻灯片相关联。例如,当我迭代幻灯片的 .CustomLayout.Shapes.Placeholders
时,我可以通过 .Name
属性.
轻松识别特定的占位符
HOWEVER 如果我 return this 形状,它将是自定义布局占位符,这会影响 ALL 此布局上的幻灯片(例如,如果我向此占位符添加文本,它会更新使用此布局的所有幻灯片!)。显然这是不可取的!
如果相反,我对集合进行索引,并尝试 return 该索引位置的形状,从幻灯片的 .Shapes.Placeholders
,看起来它们没有保持相同的索引,即, .Shapes.Placeholders(i) <> .CustomLayout.Shapes.Placholders(i)
尝试的解决方法:
我想我也许可以操纵自定义布局以向形状添加 Tag
。我试过了,但由于同样的原因失败了(即 CustomLayout.Shape 在某种程度上不是 "same" 的形状,因为 Slide.Shape...)。无论如何,如果存在这种情况,我希望避免 "workaround" 而采用更合适的方法来做到这一点。
这是我目前拥有的功能:
Function GetShapeByPlaceholderName(sName As String, sld As Slide) As Object
Dim plchldrs As Placeholders
Dim shp As Shape
Dim ret As Shape
Dim i As Long
For Each shp In sld.CustomLayout.Shapes.Placeholders
i = i + 1
If shp.Name = sName Then
'####
' This can easily identify the CustomLayout.Shapes.PLACEHOLDER
'
' But I need to return the SHAPE in the Slide.Shapes collection
'####
'###
Set ret = shp 'This will return the CustomLayout.Placeholder, which affects ALL slides
'###
'Set ret = sld.Shapes.Placeholders(i) 'the index of the Shapes.Placeholders is NOT the same
'###
'Set ret = sld.Shapes.Placeholders.FindByName(sName) 'This returns an error/specified shape name does not exist
'###
'Set ret = sld.Shapes.Placeholders.FindByName(i) 'This observes same failure that the index of the collections is not the same
Exit For
End If
Next
Set GetShapeByPlaceholderName = ret
End Function
我目前的解决方法是执行以下操作:
Delcare a module-level Dictionary
object,它根据幻灯片的 CustomLayout
和每个占位符的已知索引创建一种哈希 table Slide.Shapes
collection 内。 (这是我通过一次性子例程中的简单 FOr/Next 迭代获得的)。
由于我是从模板构建幻灯片,我认为这是相对安全可靠的,但是 不 灵活(使用 POTX 模板[的全部意义] =35=] 文件应该 易于使用 和灵活性...)。
Dim dictShapes As Object 'Dictionary
然后根据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
我这样称呼这个函数:
Dim shp as Object 'PowerPoint.Shape
Set shp = GetShapeByIndex(shp.Parent, dictShapes("chart RIGHT"))
字典以我可以传递字符串参数的方式初始化,它将 return 形状的索引,所有 应该 工作。
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 = ret
End Function
我有一个可能的解决方案。
问题出在幻灯片母版上的页脚、页码和日期占位符。它们包含在幻灯片母版上的占位符集合中,但是当创建单个幻灯片时,它们成为幻灯片的自己的属性(在 .HeaderFooter
属性 下)。这会导致母版和幻灯片上的占位符数量不同,并且由于这些占位符可能位于集合的中间,因此索引不对齐。
因此,一种可能的解决方案是从您的母版中删除这三个占位符,方法是打开幻灯片母版并取消选中页脚复选框。如果这样做,您会发现母版和幻灯片上的占位符数量相同,并且所有索引号都对齐。您仍然无法使用 SlideMaster.CustomLayouts(n).Shapes.Placeholders(m).Name
属性 访问实际幻灯片上的正确占位符。但是,一旦您知道占位符的索引(在我最后一句话的示例中为 "m"),您应该能够通过 SlideObj.Shapes.PlaceHolders(m)
访问幻灯片上的正确占位符。您可以先遍历 SlideMaster.Shapes.PlaceHolders 并存储索引供以后使用。
如果您需要页脚字段,只需将新的文本占位符添加到您的幻灯片母版,将它们放在幻灯片的底部,然后将页码、日期或固定文本插入其中。
总结:
取消选中您关心的所有幻灯片母版上的“页脚”复选框。不确定这是否可以通过编程方式完成。
为每个幻灯片母版(自定义布局)遍历 ActivePresentation.SlideMaster.CustomLayout(n).Shapes.Placeholders
查看 .Name 属性 以找到您感兴趣的占位符。存储在数组中(将使用占位符的名称作为数组名称,因此如果占位符名称是 "datatable" 我将使用数据表 [n])= CustomLayout/Master 上占位符的索引 #。这样做一次并将其存储在全局变量中。
当您想访问幻灯片上的占位符时,使用 SM_index=SlideObj.CustomFormat.Index 获取幻灯片的 SlideMaster 索引。然后使用 SlideObj.Shapes.Placeholders(datatable[SM_index])
访问占位符 "datatable"
如果您的所有幻灯片只有一个 SlideMaster,那么您不需要数组,而是可以使用一个简单的变量。
如果您需要实际代码,请告诉我——但我希望您不需要。让我知道这是否适用于您的真实世界项目。
我有另一个解决方法。我遍历幻灯片中的所有形状,并将它们与自定义布局中形状的某些形状属性进行比较。我取了宽度、高度和自动形状类型。如果完全一样我已经在幻灯片中找到了对应的形状
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
我正在尝试创建一个函数,它将 return 一个特定的形状,基于分配给 [=11= 的 已知 名称 属性 ] 目的。我不能使用形状 .Name
因为这是事先不知道的,即使在从 template/layout.
挑战似乎在于自定义布局如何与实际幻灯片相关联。例如,当我迭代幻灯片的 .CustomLayout.Shapes.Placeholders
时,我可以通过 .Name
属性.
HOWEVER 如果我 return this 形状,它将是自定义布局占位符,这会影响 ALL 此布局上的幻灯片(例如,如果我向此占位符添加文本,它会更新使用此布局的所有幻灯片!)。显然这是不可取的!
如果相反,我对集合进行索引,并尝试 return 该索引位置的形状,从幻灯片的 .Shapes.Placeholders
,看起来它们没有保持相同的索引,即, .Shapes.Placeholders(i) <> .CustomLayout.Shapes.Placholders(i)
尝试的解决方法:
我想我也许可以操纵自定义布局以向形状添加 Tag
。我试过了,但由于同样的原因失败了(即 CustomLayout.Shape 在某种程度上不是 "same" 的形状,因为 Slide.Shape...)。无论如何,如果存在这种情况,我希望避免 "workaround" 而采用更合适的方法来做到这一点。
这是我目前拥有的功能:
Function GetShapeByPlaceholderName(sName As String, sld As Slide) As Object
Dim plchldrs As Placeholders
Dim shp As Shape
Dim ret As Shape
Dim i As Long
For Each shp In sld.CustomLayout.Shapes.Placeholders
i = i + 1
If shp.Name = sName Then
'####
' This can easily identify the CustomLayout.Shapes.PLACEHOLDER
'
' But I need to return the SHAPE in the Slide.Shapes collection
'####
'###
Set ret = shp 'This will return the CustomLayout.Placeholder, which affects ALL slides
'###
'Set ret = sld.Shapes.Placeholders(i) 'the index of the Shapes.Placeholders is NOT the same
'###
'Set ret = sld.Shapes.Placeholders.FindByName(sName) 'This returns an error/specified shape name does not exist
'###
'Set ret = sld.Shapes.Placeholders.FindByName(i) 'This observes same failure that the index of the collections is not the same
Exit For
End If
Next
Set GetShapeByPlaceholderName = ret
End Function
我目前的解决方法是执行以下操作:
Delcare a module-level Dictionary
object,它根据幻灯片的 CustomLayout
和每个占位符的已知索引创建一种哈希 table Slide.Shapes
collection 内。 (这是我通过一次性子例程中的简单 FOr/Next 迭代获得的)。
由于我是从模板构建幻灯片,我认为这是相对安全可靠的,但是 不 灵活(使用 POTX 模板[的全部意义] =35=] 文件应该 易于使用 和灵活性...)。
Dim dictShapes As Object 'Dictionary
然后根据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
我这样称呼这个函数:
Dim shp as Object 'PowerPoint.Shape
Set shp = GetShapeByIndex(shp.Parent, dictShapes("chart RIGHT"))
字典以我可以传递字符串参数的方式初始化,它将 return 形状的索引,所有 应该 工作。
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 = ret
End Function
我有一个可能的解决方案。
问题出在幻灯片母版上的页脚、页码和日期占位符。它们包含在幻灯片母版上的占位符集合中,但是当创建单个幻灯片时,它们成为幻灯片的自己的属性(在 .HeaderFooter
属性 下)。这会导致母版和幻灯片上的占位符数量不同,并且由于这些占位符可能位于集合的中间,因此索引不对齐。
因此,一种可能的解决方案是从您的母版中删除这三个占位符,方法是打开幻灯片母版并取消选中页脚复选框。如果这样做,您会发现母版和幻灯片上的占位符数量相同,并且所有索引号都对齐。您仍然无法使用 SlideMaster.CustomLayouts(n).Shapes.Placeholders(m).Name
属性 访问实际幻灯片上的正确占位符。但是,一旦您知道占位符的索引(在我最后一句话的示例中为 "m"),您应该能够通过 SlideObj.Shapes.PlaceHolders(m)
访问幻灯片上的正确占位符。您可以先遍历 SlideMaster.Shapes.PlaceHolders 并存储索引供以后使用。
如果您需要页脚字段,只需将新的文本占位符添加到您的幻灯片母版,将它们放在幻灯片的底部,然后将页码、日期或固定文本插入其中。
总结:
取消选中您关心的所有幻灯片母版上的“页脚”复选框。不确定这是否可以通过编程方式完成。
为每个幻灯片母版(自定义布局)遍历
ActivePresentation.SlideMaster.CustomLayout(n).Shapes.Placeholders
查看 .Name 属性 以找到您感兴趣的占位符。存储在数组中(将使用占位符的名称作为数组名称,因此如果占位符名称是 "datatable" 我将使用数据表 [n])= CustomLayout/Master 上占位符的索引 #。这样做一次并将其存储在全局变量中。当您想访问幻灯片上的占位符时,使用 SM_index=SlideObj.CustomFormat.Index 获取幻灯片的 SlideMaster 索引。然后使用 SlideObj.Shapes.Placeholders(datatable[SM_index])
访问占位符 "datatable"
如果您的所有幻灯片只有一个 SlideMaster,那么您不需要数组,而是可以使用一个简单的变量。
如果您需要实际代码,请告诉我——但我希望您不需要。让我知道这是否适用于您的真实世界项目。
我有另一个解决方法。我遍历幻灯片中的所有形状,并将它们与自定义布局中形状的某些形状属性进行比较。我取了宽度、高度和自动形状类型。如果完全一样我已经在幻灯片中找到了对应的形状
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