🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の PowerPoint 操作 — スライド作成、グラフの貼り付け、そしてユーザーのプレゼンを閉じない終わらせ方

|

Excel VBA の PowerPoint 操作 — スライド作成、グラフの貼り付け、そしてユーザーのプレゼンを閉じない終わらせ方

TL;DR — Excel から見ると、PowerPoint はオブジェクトモデルを通して操る別のプログラムです。構造は Application > Presentations > Slides > Shapes で、セルはありません。スライドは ポイント 単位で図形を配置するキャンバスなので、数値やグラフは Excel で用意し、PowerPoint はそれを配置するだけにします。落とし穴は、PowerPoint が 一つしか起動しない ことです。CreateObject("PowerPoint.Application") が返すのは、ユーザーがすでに開いている、ユーザーのプレゼンテーションが入った PowerPoint そのものです。閉じるのは自分で作ったプレゼンテーションだけにし、.Quit を呼ぶのはマクロの開始前に PowerPoint が起動していなかった場合に限ります。グラフは 図 として貼り付け、クリップボードが遅いときは貼り付けを再試行し、レイアウトをコードで描く代わりにテンプレートから組み立てましょう。

Sub ChartToNewSlide()
    Dim ppt As Object, pres As Object, sld As Object
    Set ppt = CreateObject("PowerPoint.Application")     ' 起動中の PowerPoint があればそれ
    Set pres = ppt.Presentations.Add                      ' ウィンドウ付きの新しいプレゼン
    Set sld = pres.Slides.Add(1, 11)                      ' 11 = ppLayoutTitleOnly
    sld.Shapes.Title.TextFrame.TextRange.Text = "Q3 revenue"
    ActiveSheet.ChartObjects(1).Chart.CopyPicture
    sld.Shapes.PasteSpecial DataType:=2                   ' 2 = ppPasteEnhancedMetafile
End Sub

この記事は、Excel から他の Office アプリを操作する 三部構成シリーズの第一回です。ここで扱うのは PowerPoint、つまり図形の集まりとしてのプレゼンテーションです。Word のガイド では、一続きの長いテキストである文書を扱います。参照設定のガイド では、相手のプログラムの語彙を VBA に教えるつながりと、それが他人の PC で欠けていたときに何が起きるかを扱います。三つに共通するルールは一つです。どのオブジェクトもいずれか一つのアプリケーションに属している。だから、どのアプリのものかを明示する。

この記事で学べること

  • 考え方の軸:プレゼンテーションはスライドに載った図形の集まりで、単位はポイント、セルはない
  • PowerPoint が一つしか起動しないことで .Quit が危険になる理由と、安全な始め方・終わらせ方
  • 参照設定なしでスライドを追加し、タイトルを書き、レイアウト番号を使う方法
  • グラフやセル範囲を図として貼り付ける方法と、貼り付けがときどき失敗する理由
  • 貼り付けた図形をスライド上に配置し、サイズを合わせる方法
  • レイアウトをコードで作るよりテンプレートのほうが優れている理由

考え方の軸:セルはなく、キャンバスに図形があるだけ

Excel はグリッドで考えます。PowerPoint にはグリッドがありません。そのオブジェクトモデルは短い連鎖です。

オブジェクト 何を表すか Excel での対応
Application PowerPoint というプログラム Application
Presentations / Presentation 開いているプレゼン一覧 / 一つのプレゼン Workbooks / Workbook
Slides / Slide プレゼンのページ Worksheets / Worksheet
Shapes / Shape スライド上のすべて:タイトル、テキストボックス、画像、グラフ (実質的な対応なし)

テキストは図形の中にあります:Shape.TextFrame.TextRange.Text。位置は図形が持っています:.Left、.Top、.Width、.Height で、どれも ポイント 単位(1 インチ = 72 ポイント)です。スライド自体の大きさは pres.PageSetup.SlideWidth × SlideHeight で、標準の 16:9 なら 960 × 540 ポイントです。

だからこそ、仕事の分担は Excel が計算し、PowerPoint が配置する のが理にかなっています。数式や書式が使えるシート上で表やグラフを完成させ、その完成品の図をスライドに移すのです。PowerPoint の中でセルを一つずつ埋めて表を組み立てるやり方は、遅くて壊れやすくなります。

落とし穴:PowerPoint は一つしか起動しない

Excel や Word は同時に複数起動できます。PowerPoint はできません。マクロが CreateObject("PowerPoint.Application") を呼んでも、CreateObject のガイド で説明した多くのプログラムのように、Windows が新しい専用の PowerPoint を起動してくれるわけではありません。返ってくるのはすでに起動している PowerPoint、つまりユーザーが作りかけのプレゼンテーションを開いている、その PowerPoint です。

ここから二つのことが言えます。

  • ppt.Quit はすべてを閉じます。 ユーザーが開いているプレゼンテーションがすべて閉じられ、未保存の変更があれば保存の確認が出ます。コードで確認を抑止していれば、変更は失われます。
  • 非表示にはできません。 ppt.Visible = False は、Hiding the application window is not allowed(アプリケーション ウィンドウを非表示にすることはできません)で終わる実行時エラーになります。見えないところで作業したいなら、プログラムを隠すのではなく、プレゼンテーションをウィンドウなし(WithWindow:=0)で開くか追加します。

安全なパターンは、PowerPoint がもともと起動していたかを覚えておき、自分で開いたものだけを閉じ、自分で起動したものだけを終了することです。

Sub BuildDeck()
    Dim ppt As Object, pres As Object
    Dim wasRunning As Boolean

    On Error Resume Next
    Set ppt = GetObject(, "PowerPoint.Application")   ' すでに起動しているか?
    On Error GoTo 0
    wasRunning = Not ppt Is Nothing
    If Not wasRunning Then Set ppt = CreateObject("PowerPoint.Application")

    Set pres = ppt.Presentations.Add
    ' ... ここでスライドと内容を追加 ...
    pres.SaveAs ThisWorkbook.Path & "\Report.pptx"
    pres.Close                                        ' 閉じるのは自分のプレゼンだけ

    If Not wasRunning Then
        If ppt.Presentations.Count = 0 Then ppt.Quit  ' 終了するのは自分で起動した場合だけ
    End If
    Set pres = Nothing
    Set ppt = Nothing
End Sub

第一引数を空にした GetObject は、起動中のインスタンスにつなぎ、なければ失敗します。これがまさに必要な判定です。最後に Set ... = Nothing で変数を解放するのは、Nothing のガイド のとおりです。

参照設定なしでスライドとテキストを追加する

pres.Slides.Add(Index, Layout) は、指定した位置に PowerPoint の組み込みレイアウトでスライドを挿入します。PowerPoint ライブラリへの参照設定がなければ、ppLayoutTitleOnly のようなレイアウト名は Excel のコンパイラにとって意味を持たないので、番号を使います。一度だけ定数として宣言しておけば、コードは読みやすいままです。

Const ppLayoutTitle As Long = 1
Const ppLayoutTitleOnly As Long = 11
Const ppLayoutBlank As Long = 12
Const ppPasteEnhancedMetafile As Long = 2
Const ppPastePNG As Long = 6

Sub AddSlides(pres As Object)
    Dim sld As Object
    Set sld = pres.Slides.Add(pres.Slides.Count + 1, ppLayoutTitleOnly)
    sld.Shapes.Title.TextFrame.TextRange.Text = "Sales by region"

    Set sld = pres.Slides.Add(pres.Slides.Count + 1, ppLayoutBlank)
    With sld.Shapes.AddTextbox(1, 40, 40, 600, 50)    ' 1 = 横書き
        .TextFrame.TextRange.Text = "Notes for the board"
        .TextFrame.TextRange.Font.Size = 24
    End With
End Sub

pres.Slides.Count + 1 は末尾に追加します。IntelliSense と本来の名前を使いたいなら、PowerPoint のオブジェクト ライブラリへの参照設定をします。その方法と、ファイルを配布したときに払う代償は 参照設定のガイド で説明しています。

グラフやセル範囲の貼り付け:図にして、再試行する

Excel の内容をスライドへ確実に移す方法は、図として貼り付けることです。グラフならこうです。

ws.ChartObjects("chtSales").Chart.CopyPicture   ' グラフの図をコピー
Set shp = sld.Shapes.PasteSpecial(DataType:=ppPasteEnhancedMetafile)

セル範囲なら、シート上の見た目そのままの書式でこうします。

ws.Range("A1:E12").CopyPicture Appearance:=1, Format:=-4147   ' xlScreen, xlPicture
Set shp = sld.Shapes.PasteSpecial(DataType:=ppPasteEnhancedMetafile)

拡張メタファイルは、スライド上で拡大縮小してもくっきりしたままです。ppPastePNG は解像度が固定された画像になり、どの PC でもまったく同じに見えます。どちらもスナップショットなので、ブックが変わっても変化しません。レポートとしては、たいていそれが望ましい動きです。

ここで、誰もが一度は出会う失敗があります。マクロは十回のうち九回は動くのに、ある回だけ貼り付けで止まり、クリップボードが空だとか、ここには貼り付けられないデータだとかいうエラーが出ます。コードには何の問題もありません。PowerPoint が要求した時点で、コピーした内容がまだ Windows のクリップボードに描画されている途中なのです。直し方は、あちこちに固定の Wait を入れることではなく、時間を与えて再試行することです。

Function PasteWithRetry(sld As Object, ByVal dataType As Long) As Object
    Dim attempt As Long
    For attempt = 1 To 5
        On Error Resume Next
        Set PasteWithRetry = sld.Shapes.PasteSpecial(DataType:=dataType)
        If Err.Number = 0 Then
            On Error GoTo 0
            Exit Function
        End If
        On Error GoTo 0
        DoEvents                                 ' クリップボードの処理を終わらせる
        Application.Wait Now + TimeSerial(0, 0, 1)
    Next attempt
    Err.Raise vbObjectError + 513, , "Paste into PowerPoint failed after 5 tries"
End Function

ここで制御を譲ることがなぜ効くのかは DoEvents のガイド で説明しています。コピーしたらすぐ PasteWithRetry を呼ぶ、を一項目ずつ繰り返します。グラフを五つまとめてコピーしてから五回貼り付ける、というやり方は決してしないでください。

貼り付けた図形を配置する

PasteSpecial は新しい図形を(ShapeRange として)返すので、すぐに位置を決められます。固定の数値ではなくスライドの大きさを使えば、同じコードが 4:3 でも 16:9 でも動きます。

Sub FitToSlide(pres As Object, shp As Object, ByVal topMargin As Single)
    Dim maxW As Single, maxH As Single
    maxW = pres.PageSetup.SlideWidth - 80
    maxH = pres.PageSetup.SlideHeight - topMargin - 40
    shp.LockAspectRatio = -1                       ' msoTrue
    shp.Width = maxW
    If shp.Height > maxH Then shp.Height = maxH    ' 縦横比の固定で幅も連動する
    shp.Left = (pres.PageSetup.SlideWidth - shp.Width) / 2
    shp.Top = topMargin
End Sub

縦横比を固定しておけば、幅を変えると高さも変わるので、図が引き伸ばされることはありません。中央揃えは、スライドの幅から図形の幅を引いて半分にするだけです。

判断の分かれ目:スライドはコードで描かず、テンプレートに差し込む

VBA で位置を決めたピクセルは、来月には誰かに「動かして」と言われるピクセルです。私のルールは、プレゼンテーションのデザインは PowerPoint のテンプレートに持たせ、マクロはそこに差し込むだけにする です。フォント、配色、ロゴを整えたプレゼンテーションを一つ手作業で作ります。コードが埋める図形には、選択ウィンドウ(Selection Pane、Alt+F10)で txtTitle や picChart のような名前を付けます。あとはマクロがそのコピーを開き、名前で図形を埋めます。

Set pres = ppt.Presentations.Open(FileName:=ThisWorkbook.Path & "\Monthly.potx", _
                                  ReadOnly:=-1, Untitled:=-1)   ' 無題のコピーとして開く
With pres.Slides(1)
    .Shapes("txtTitle").TextFrame.TextRange.Text = "Sales - " & Format(Date, "mmmm yyyy")
    .Shapes("txtTotal").TextFrame.TextRange.Text = Format(ws.Range("F2").Value, "#,##0")
End With

マーケティング部門がブランドカラーを変えても、編集するのはテンプレートで、コードは変わりません。同じ理屈で、リンクしたグラフではなく図を貼り付けるべきです。ブックへのリンクはプレゼンテーションをメールで送った瞬間に切れ、受け取った人には届かないリンクの更新を求めることになります。プレゼンテーションを常に最新に保つ必要があるなら、データは Excel に置いたままマクロを再実行します。PDF だけが必要なら、PowerPoint をまったく使わずに PDF 保存のガイド の方法で足りるかもしれません。

ExcelMaster の活用

PowerPoint の自動化は、コードを見ただけでは分かりにくい形で失敗します。十回に一回だけ失敗する貼り付け、ユーザーの他のプレゼンテーションまで閉じてしまうマクロ、作った人の画面でだけ正しく見えるレイアウト。

ExcelMaster には、作りたいプレゼンテーションをそのまま伝えられます。たとえば「地域ごとに一枚、グラフを載せてタイトルに合計を入れて」。すると、安全な始め方と終わらせ方、再試行付きの貼り付け、スライドの寸法から決める図形サイズを備えたマクロを書き、デザインをハードコードする代わりにあなたのテンプレートに差し込みます。

よくある質問

Excel VBA から PowerPoint を開くには?

CreateObject("PowerPoint.Application") を使い、新しいプレゼンテーションなら Presentations.Add、既存のファイルなら Presentations.Open を呼びます。PowerPoint は一つしか起動しないので、先に GetObject(, "PowerPoint.Application") ですでに起動していたかを確認し、最後に終了してよいかどうかを判断できるようにしておきます。

VBA で Excel のグラフを PowerPoint にコピーするには?

グラフで Chart.CopyPicture を呼び、続けて Slide.Shapes.PasteSpecial を DataType:=2(ppPasteEnhancedMetafile)または 6(ppPastePNG)で呼びます。クリップボードの準備が間に合わないことがあるので、コピーのたびにすぐ貼り付け、間に DoEvents を挟んで数回再試行します。

PowerPoint への VBA の貼り付けがランダムに失敗するのはなぜですか?

PowerPoint が貼り付けようとした時点で、コピーした内容がまだ Windows のクリップボードに届ききっていないからです。DoEvents と 1 秒の待機を挟んだ短いループで貼り付けを再試行し、各項目はコピーした直後に貼り付けます。

マクロがユーザーの他のプレゼンテーションまで閉じてしまうのはなぜですか?

PowerPoint はシングルインスタンスのプログラムなので、マクロはユーザーが開いているすべてのプレゼンテーションと同じ PowerPoint を共有しており、Application.Quit はそれらをすべて閉じてしまいます。閉じるのはコードが作ったプレゼンテーションだけにし、終了するのはマクロ開始時に PowerPoint が起動しておらず、かつプレゼンテーションが一つも残っていない場合だけにします。

VBA で PowerPoint を非表示のまま実行できますか?

プログラムを隠す方法ではできません。Visible を False にするとエラーになります。代わりに WithWindow:=0 でプレゼンテーションをウィンドウなしで追加するか開けば、ユーザーの PowerPoint ウィンドウはそのままです。

検証環境

検証環境: Excel 365 と PowerPoint 365 (Windows 11)、VBA 7.1 — 最終確認 2026-10-02。

関連ガイド: VBA Word · VBA 参照設定 · VBA CreateObject · VBA Outlook · VBA グラフ · VBA PDF 保存 · VBA DoEvents · VBA Nothing