ExcelからPowerPointへの図表貼り付けVBA

パフォーマンスモニタの監視データ(blg)に基づいてPowerPointで報告用のレポートを作成する必要がありました。パフォーマンスログのデータをCSVに変換してExcelに取り込んでグラフを作成し、そのグラフをPowerPointに貼り付ける形で実現しようと考えました。
ここでは、Excelの図表をPowerPointに貼り付ける作業をVBAで実現します。
ちなみにPowerShellでも実現できるのですが2019年時点ではVBAを推奨します。詳細はこちらをご覧ください。

概要

Excel上のグラフや表領域をPowerPointの各スライドに貼り付けるExcel VBAを紹介します。

前提

  • パフォーマンスモニタのログファイルをExcelにインポートしてグラフや表を作成する処理については、ここでは扱いません。(別途記事を投稿予定です。)
  • Microsoft Excel 2013/PowerPoint2013、Excel 2010/PowerPoint 2010を対象とします。それ以外の環境では動作確認できていません。
  • コピー元となるExcelファイルのグラフや表、コピー先となるPowerPointファイル上の表等を事前に用意している前提です。
  • 技術検証のためのサンプルであり、業務で使用する場合は適宜変更してください。

考察

検証を通して理解したことや気づいたことです。

  • Excel上のグラフオブジェクトは、”Worksheet.ChartObjects(name)”で参照できます。引数にはインデックスか名前を指定できます。Excelでグラフオブジェクト等に名前を設定する場合、[ホーム]タブの[検索と選択]-[オブジェクトの選択と表示]から行います。
  • PowerPoint上の表オブジェクトは、”Slide.Shapes(name).Table.Cell(row, col)”で参照できます。同様に名前を設定する場合、[ホーム]タブの[選択]-[オブジェクトの選択と表示]から行います。
  • Excelの図表をコピーし、PowerPointに張り付ける場合、Windowsのクリップボードを中継することになります。Excel VBAでブックやシート等のExcel上の操作を行う場合は同期処理(個々の操作が完了してから次の処理に進む)となりますが、Excelからの「クリップボード操作」「PowerPoint操作」は非同期処理(それぞれの操作が完了する前に次の処理に進む)となります。そのため、単純にExcelからコピーしてPowerPointに貼り付けを行うと、Excelからクリップボードへの図表コピーが完了する前に、クリップボードからPowerPointへの貼り付けが開始され、期待した通りに動作しない場合があります。
  • 個々の操作が完了したかの確認を行えるAPIは存在せず、独自に回避策の実装が必要となります。一番簡単で確実なのはスリープすることです。ただし、この辺の事象の発生はPowerPointのバージョンで異なりますが、新しいバージョンの方が安定している感がします。
    手段概要
    コピー後の待機時間を設ける確実にコピーが完了できるよう、コピー開始後に所定時間待機する方法です。
    待機時間に比例して貼り付けの成功率は上がりますが、トータルの処理時間が長くなります。また、環境や処理対象データによって時間の調整が必要となります。
    貼り付けをリトライする貼り付け失敗時に再度貼り付けする方法です。
    コピーと貼り付け操作は環境依存のようで、PowerPoint2013では有効でしたが、PowerPoint2010では貼り付け失敗時にコピーデータが失われている状態でありリトライに意味がありませんでした。(コピーからリトライすればいいのかもしれません。)
    独自に値を設定する
    (コピペは断念)
    貼り付けようとしている値をプログラムで値設定する方法です。
    例えば表のセル領域をコピーするのではなく、セル個別の値を取得し、貼り付け先のセル個別に値を設定するイメージです。クリップボードを使わないので確実ですが、コード量が増えることや、複雑な値設定は困難です。
  • 待機時間を設ける場合、VBA以外の動作がフリーズしてしまうので、前後にDoEventsを実行しましょう。DoEventsを実行することで、OS側で管理している他のアプリのイベントを処理できます。(DoEventsがないと、スリープしてもクリップボードへのコピーが開始されない可能性があるため。)
  • PowerPointへの図の貼り付けのために”CommandBars.ExecuteMso(idMso)”を使用しています。これはリボン等のUI上のコマンドを実行するためのコマンドです。引数(idMso)には様々なものを指定可能であり、詳細はこちらで確認できます。

サンプルの説明

サンプルの構成

今回のサンプルは、VBAを格納するCopyMacro.xlsm、コピー元の図表を格納するグラフテンプレート.xlsx、図表の貼り付け先となるサンプルレポート.pptx、という3つのファイルで構成しています。
CopyMacro.xlsmのVBAを実行すると、グラフテンプレート上の各シートにある図表をコピーし、サンプルレポート上の各スライドに順番に張り付けていきます。本来であれば、数十個の図表をレポートに張り付ける必要があったのですが、今回は検証目的であるため、グラフテンプレート上の3シート分の図表を、サンプルレポートの10スライドに貼り付けます。(Excelの最初の2つの図表は、PowerPointのスライド2,3に貼り付けます。Excelの3つ目の図表を、PowerPointのスライド4以降に繰り返し貼り付けます。)

これらのファイルはこちらからダウンロードできます。

ファイル名説明
CopyMacro.xlsm下記サンプルコードを含むマクロファイルです。
グラフテンプレート.xlsxサンプルのグラフと表(コピー元)です。
シート”01″に図表、その元となるデータが”01data”シートに定義されています。同様に、”02″/”02data”, “0X”/”0Xdata”シートを格納します。
コピー元となるグラフ(chart)を識別できるよう、[オブジェクトの選択と表示]を使って各シートの対象グラフに”graph”という名前を設定しています。
サンプルレポート.pptxサンプルのレポート(コピー先)です。
貼り付け先となる表を識別できるよう、[オブジェクトの選択と表示]を使って各スライドの対象表に”main_table”という名前を設定しています。

実行方法

CopyMacro.xlsmを開き、[開発タブ]-[Visual Basic]をクリックします。
起動した[Microsoft Visual Basic for Applications]ウインドウで、再生ボタンをクリックします。
マクロ名でCopyXlsToPptを選択し、[実行]をクリックします。

サンプルプログラム

サンプルプログラムは次の通りです。

  • PowerPoint操作、クリップボード操作(DataObject)を行うためにVBAの参照設定でDLLを追加しています。クリップボード操作を行うためのライブラリは参照設定の一覧から選択できないため、”C:\Windows\System32\FM20.dll”を参照しています。
  • Sleep関数はkernel32のものを使用しています。(処理時間がかかるDoEventsを繰り返し実行して待機する方法もありますが、今回はSleep関数を使うことにしました。)
  • 表領域の貼り付けに関して、PowerPoint2013では”PowerPoint.Application.CommandBars.ExecuteMso”でさくさく貼り付けできたのですが、PowerPoint2010での最初の貼り付けに5秒程かかりました。そのため、PowerPoint2013環境では”PowerPoint.Application.ActiveWindow.View.PasteSpecial”を使用しています。(二つのコマンドで若干貼り付けの書式が違うようですが、そこは割り切りました。)
  • グラフ貼り付けで使っているPasteSpecial()のリトライ処理は、PowerPoint2013でしか確認できていません。PowerPoint2010環境では、コピー元が不正となるためリトライしても正常に貼り付けできません。
  • PowerPoint系のAPIから返却されるオブジェクトを代入時の型不一致エラーがでる場合があります。返却値を入れるDim宣言では、”Dim shape As PowerPoint.Shape”等のようにPowerPointのクラスであることを宣言した方が安全です。
  • PowerPoint張り付き先のグラフ座標はPowerPointで確認した結果を入力できるようcm単位にしています。
  • 待ち時間(PHASE_INTERVAL, OPE_INTERVAL, COPY_INTERVAL)は、実行環境や対象ファイルに応じて、適宜調整してください。