Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

13 Jan 2021

初探PowerPont的VBA

  • VBA是MS Office的标准脚本语言。普通的pptx结尾的PowerPoint文件无法保存VBA脚本,只有以pptm结尾的文件可以。
  • MS Office自带VBA的开发工具,在Ribbon中开启Develop Tab才能看到VBA开发工具的启动按钮。对于属于Visual Studio的,VBA的开发工具应该可以很快上手。

技巧一,使用Debugger查看物件属性

VBA开发工具中竟然没有办法像浏览器的开发工具那样,可以有检视工具,用来对Office文档中的物件进行检视。一个变通的办法是使用Debug工具。

首先输入以下代码

Sub ShowIt()
  Set ActiveShape = ActiveWindow.Selection.ShapeRange(1)
End Sub

然后在Set ActiveShape = ActiveWindow.Selection.ShapeRange(1)打断点,接着执行这个脚本,就可以在VBA开发工具里面查看ActiveShape的属性了。

Determine The Current ActiveShape In PowerPoint With VBA

任务一,处理PowerPoint事件

PowerPoint的事件都集中在Application对象。挂载事件处理函数需要特殊的设置,参考Use Events with the Application Object

' in Module1
Public WithEvents App As Application

Private Sub App_SlideSelectionChanged(ByVal SldRange As SlideRange)
  If SldRange.Count > 0 Then
    Debug.Print SldRange(1).Name
  End If
End Sub

' in Class1
Dim X As New Class1
Sub InitializeApp()
    Set X.App = Application
End Sub

上面处理的是SlideSelectionChanged 事件。

任务二,为选中的一个Section下的Slides添加目录页

Public Function AddTocSlideForSelectedSlides() As slide
  Dim index As Long
  Set oCustomLayout = ActivePresentation.Designs(1).SlideMaster.CustomLayouts(23)
  index = ActiveWindow.Selection.SlideRange(1).SlideIndex
  Set oNewSlide = ActivePresentation.Slides.AddSlide(index + 1, oCustomLayout)
  ActivePresentation.Slides(index).MoveTo (index + 1)
  Set AddTocSlideForSelectedSlides = oNewSlide
End Function
Public Function GetSectionName() As String
  sectionIndex = ActiveWindow.Selection.SlideRange(1).sectionIndex
  GetSectionName = ActivePresentation.SectionProperties.Name(sectionIndex)
End Function
Sub AddTocWithHyperlinksForSelectedSlides()
  Dim oSlide As slide
  Set oTocSlide = AddTocSlideForSelectedSlides()
  oTocSlide.Shapes.Title.TextFrame.TextRange = GetSectionName()
  oTocSlide.Shapes(2).TextFrame2.Column.Number = 2
  Set bodyContent = oTocSlide.Shapes.Placeholders(2).TextFrame
  For Each oSlide In ActiveWindow.Selection.SlideRange
    If oSlide.Shapes.HasTitle Then
      Set oTitle = oSlide.Shapes.Title.TextFrame.TextRange
      titleText = RTrim(oTitle.Text)
      If Right(titleText, 1) = Chr(11) Then titleText = Left(titleText, Len(titleText) - 1)
      bodyContent.TextRange.InsertAfter (titleText & Chr(11) & "(link)" & Chr(13))
      linkStart = InStrRev(bodyContent.TextRange.Text, "(link)")
      With bodyContent.TextRange.Characters(linkStart, Len("(link)")).ActionSettings(ppMouseClick).Hyperlink
        .SubAddress = oSlide.SlideID & "," & oSlide.SlideIndex & "," & titleText
      End With
    End If
  Next
End Sub

上面的代码参考了 Powerpoint - creating a hyperlink table of contents using vba

任务三,创建一个PowerPoint Add-in

参考Quick Access Toolbar - MS PowerPoint 2013 ,在PowerPoint里面,可以直接在Ribbon上添加Custom Macro,可是这个Custom Macro会锁定在某个文件。比如MyFile.PPTM!MySubroutine这个例子中,这个Custom Macro对应的是MyFile.PPTM中的MySubroutine。要使用这个Custom Macro,必须保持MyFile.PPTM处于打开状态。

Creating PowerPoint Add-Ins from VBA defined Macros ,可以把一个PPTM文件保存成一个PPAM文件,默认情况下保存的路径是%appdata%\Microsoft\AddIns底下。但是如何加载这个Add-in,需要参考Add or load a PowerPoint add-in

但是默认情况下,但是PPAM中的宏无法直接加载,除非通过Edit a .ppam file for customizing an add-in 记述的办法修改注册表:

HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\PowerPoint\Options

(That'd be for PPT 2010; substitute 16.0 in place of 14.0 for PPT 2016/365 and PPT 2019, 15.0 for PPT 2013, 12.0 for PPT 2007 and so on ... there's no 13.0)

Add a new DWORD value: DebugAddins = 1

一个变通的办法是通过CustomUI来为PPAM中的VBA添加一个UI交互控件。假设有下面的VBA代码:

Sub Hello()
  MsgBox "Hello"
End Sub

可以把下面的XML片段注入PPAM的母版,也就是PPTM:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
	<ribbon startFromScratch="false">
		<tabs>
			<tab id="CustomTab" label="Custom Tab">
				<group id="DefaultGroup" label="Default">
					<button id="helloButton" label="Hello" imageMso="HappyFace" size="large" onAction="Hello" />
				</group>
			</tab>
		</tabs>
	</ribbon>
</customUI>

其他参考

PowerPoint的文件格式pptx和pptm是基于OpenXML格式的,其规范可以参照文档[MS-PPTX] -v20201117PowerPoint (.pptx) Extensions to the Office Open XML File FormatCopyright © 2020 Microsoft CorporationRelease: November 17, 2020[MS-PPTX]: PowerPoint (.pptx) Extensions to the Office Open XML File Format

不是所有的OpenXML的特性都可以通过VBA操作。随着Office的在线化,VBA可能会式微,但应该不会消失。微软已经推出了使用JavaScript来开发Office的Add-in。但是这样的Add-in需要服务端的支持。而且相关的API也不够完备。

通过Python+Pywin32操作

通过IronPython操作

通过.NET Interactive

.Net Interactive还在开发中,但是前景喜人。作成之后应该可以使用C#作为脚本语言来操作OFFICE的COM模型。

VBA相关参考

(本篇完)