【ExcelVBA】図形を複製する

Yahoo!知恵袋に答えた中から、図形を複製する方法を紹介します。

質問

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13280040988

やりたいことは添付の画像のような形です。

H9とI9のセルに青と赤のオブジェクトが入っていると思いますが、このオブジェクトをH列とI列の値に従ってすべての行に配置したいのです。例えばH列に共通と入っていればそのセルの上に赤い角丸のオブジェクト、I列に専用と入っていればそのセルの上に青い角丸のオブジェクトを配置する、みたいな要領です。普通に複製して配置できればいいのですが、行が1000行近くあるので手作業では難しく、、、これを実現する方法を教えていただけないでしょうか、、、

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13280040988

回答

この質問には、「そんなにオブジェクト並べて何をする」のかとか、「その作業に何の意味があるのか」とか、「オブジェクトで置き換えてしまったらフィルターにもかからないし不便なことだらけでは」とか、いろいろな突っ込みが他の回答者からされていましたが、私は基本的に質問者さんの意図は深くつっこまない主義です(きっと不特定多数の人が見る掲示板には言えない事情があるだろうと思うし)ので、何も考えずにサクサクコードを書いて回答しました。

私の回答はこんな感じです。

Public Sub DuplicateShapes()
    Dim sh As Worksheet
    Set sh = ActiveSheet    '作業シート(=アクティブなシート)
   
    Dim 共通 As Shape
    Dim 専用 As Shape
    
    Set 共通 = ActiveSheet.Shapes(1)
    Set 専用 = ActiveSheet.Shapes(2)
    
    Dim lMax As Long    '最大行番号
    lMax = sh.Cells(9, "A").End(xlDown).Row 'セルA9からCtrl+↓で最終行番号をゲット
    
    Dim shp As Shape
    Dim ii As Long
    
    Const csTopMargin As Single = 2     'オブジェクト貼り付け時余白(Top側)
    Const csLeftMargin As Single = 5    'オブジェクト貼り付け時余白(Left側)
    
    Application.ScreenUpdating = False  '画面描画禁止
    For ii = 10 To lMax
    
        If sh.Cells(ii, "H").Value = "共通" Then
            Set shp = 共通.Duplicate
            shp.Top = sh.Cells(ii, "H").Top + csTopMargin   'セルのTopにオブジェクトのTopを合わせる。余白は適宜調整してください。
            shp.Left = sh.Cells(ii, "H").Left + csLeftMargin    'セルのLeftにオブジェクトのLeftを合わせる。余白は適宜調整してください。
        End If
        
        If sh.Cells(ii, "I").Value = "専用" Then
            Set shp = 専用.Duplicate
            shp.Top = sh.Cells(ii, "I").Top + csTopMargin
            shp.Left = sh.Cells(ii, "I").Left + csLeftMargin
        End If
            
    Next ii
    Application.ScreenUpdating = True '画面描画再開
    
    '後始末
    Set sh = Nothing
    Set shp = Nothing
    Set 共通 = Nothing
    Set 専用 = Nothing
    
End Sub

解説

前提

私のコードは、大前提に、最初のワークシート上に存在している図形描画が2つだけということがあります。

もし他にも図形描画が存在しているなら、

Set 共通 = ActiveSheet.Shapes(1)
Set 専用 = ActiveSheet.Shapes(2)

の部分を修正しないといけません。

図形を複製するDuplicateメソッド

ループの中で図形を複製しています。複製には、Duplicateメソッドを使っています。

Set shp = 共通.Duplicate

デバッグしてみてすぐ分かりましたが、Duplicateはメモリをフルに使うようで、動作がとても遅いです。

そこで少しでも処理が早くなるように、Application.ScreenUpdating = False という、画面描画制御をループの前後に入れることにしました。

位置調整にはTopとLeft

図形描画の位置を調整するには、TopとLeftというプロパティを使っています。

図形描画とTopとLeft

図形描画にもTopとLeftがありますが、Range(セル)にもTopとLeftがあります。

今回、対象となるセルのTopとLeftに合わせる形にしました。

サンプルを見ると、ぴったり一致ではなく、少しずれているように見えました。そこで、マージン用の定数を設け、マージンの分だけずらすようにしました。

おまけ

本日作成したものをZIPにしておいておきます。

https://kn-sharoushi.com/wp-content/uploads/2023/05/20230516chie_DuplicateShapes.zip