どうでもいいプログラム研究所

とある編集者によるIT、Web、ソフトウェア、プログラミングに関する雑記と覚え書き

ワークシート上のフォームコントロールはどうやって取得する?【VBA】

最近書いた「サクラクレパスクーピーの柄をランダムに生成するExcelマクロを考えてみた」の続きです。ワークシート上でフォームコントロールの図形を扱っていたときに少し引っかかった話です。

フォームコントロールのボタンが消えてしまった

このクーピー柄生成マクロを作っている際に、シート上に生成した図形をすべて消すため、以下のマクロを書きました。

Sub deleteAll()
   Dim shp As Shape
   For Each shp In ActiveSheet.Shapes
      shp.Delete
   Next shp
End Sub

見ておわかりの通り、アクティブなシート上に存在する図形をすべて消去するマクロです。このマクロをフォームコントロールのボタンに登録し、そのあとボタンを押して実行したのですが、

押したボタンまで消えてしまった……

まあ「そんなの当たり前だろ」って話なのですが、Shapeオブジェクト=オートシェイプくらいの認識しかなかった私は、このとき初めて「フォームコントロールもShapeオブジェクトに含まれるのか…」と思ったわけです。 

ではフォームコントロールをどうプログラムに識別させる? 

というわけで、deleteメソッドで図形のうちボタンだけを消去せずに残す対策を考えることに。Shapeオブジェクトのプロパティの中に、必ずフォームコントロールであることを指定するプロパティがあるはずなので、それを探すことにしました。

繰り返しますが、私の中でShapeオブジェクトはオートシェイプのイメージしかなかったので、当初このフォームコントロールを探すのに、AutoShapeTypeプロパティのどれに該当するのかなーという発想になり、それを探してました。ちなみに以下が公式リファレンスです。

docs.microsoft.com

当然、該当するものは見つかりません…

フォームコントロールはTypeプロパティで指定する

その後、ある人のブログを見てようやく判明。Shapeオブジェクトには、Typeプロパティというのがあって、そこでAutoShape以外のShape(例えば画像とかフォームコントロールとかテキストボックスとか)の種類を指定できるのですね。ちなみに以下が公式リファレンスです。

docs.microsoft.com

 

 今回探していたフォームコントロールmsoFormControlでと書くようです。というわけで最初に紹介したマクロは以下のように修正するのがよいでしょう。

Sub deleteAll()
    Dim shp As Shape
    For Each shp In ActiveSheet.Shapes
      If shp.Type <> msoFormControl And shp.Type <> msoPicture Then
      shp.Delete
      End If
    Next shp
End Sub

こうすれば、ボタンは消去されません。あと今回のクーピー柄生成マクロでは、柄の上にクーピーの商品名が書いてある画像ファイルを貼り付けてあり、それも消去の対象から外したいので、それも上記コード中に書いてあります。画像はmsoPictureというType名です。

まぁ「オートシェイプだけを消す」という目的なら

If shp.type = msoautoshape 

と書いて、「オートシェイプに該当したら消去」というロジックでもいいんですけどね。

以上、Shapeオブジェクト=オートシェイプと恥ずかしい思い込みをしていた私のちょっとした失敗談でした。