重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

Sub うまくいく()
Dim rng As Range, shp As Object

For Each shp In ActiveSheet.Shapes
With shp
Set rng = Range(.TopLeftCell, .BottomRightCell)
Debug.Print rng.Address
End With
Next shp

End Sub
----------------------------------------------------------------
Sub うまくいかない()
Dim rng As Range, shp As Object

Set shp = Selection.ShapeRange

With shp
Set rng = Range(.TopLeftCell, .BottomRightCell)
Debug.Print rng.Address
End With

End Sub
----------------------------------------------------------------
事前にオブジェクトを選択してからの
Set shp = Selection.ShapeRange

Set shp = ActiveSheet.Shapes.Range(Array("picture 2"))
などと直接指定してもいずれも
Set rng = Range(.TopLeftCell, .BottomRightCell)
のところで
実行時エラー '438':
オブジェクトは、このプロパティまたはメソッドをサポートしていません。
となってしまいます。

うまくいくのといかないのとの違いが判りません。どなたかお願いいたします。

A 回答 (6件)

何度もすみません。



「うまくいくほう」をF8キーでステップ実行して
「For Each shp In ActiveSheet.Shapes」の実行直後に
ローカルウィンドウで「shp」の中身(変数内に格納されたもの)を見ると、
「Object/Shape」と表示されます。


「うまくいくほう」も同じくF8キーでステップ実行して
「Set shp = Selection.ShapeRange」の実行直後に
ローカルウィンドウで「shp」の中身(変数内に格納されたもの)を見ると、
「Object/ShapeRange」と表示されます。

両者を比較すると、同じ名前・型の変数なのに・・・、

★うまくいくほうは:「Object/Shape」、
つまり、「Shapeオブジェクト」のデータが格納され、

★うまくいかないほうは:「Object/ShapeRange」、
つまり、「ShapeRangeオブジェクト」のデータが格納され

・・・ています。

そして、ヘルプにて
「Shapeオブジェクト」のオブジェクトメンバーを調べてみると、「TopLeftCell」プロパティがちゃんと存在します。「オブジェクトの左上端にあるセルを表す Range オブジェクトを返します。値の取得のみ可能です。」とあり、「うまくいくほう」の動きとも合致します。

が、「ShapeRangeオブジェクト」のほうには、ヘルプのオブジェクトメンバーを調べてみても「TopLeftCell」プロパティは存在しません。

オブジェクトブラウザで「TopLeftCell」で完全一致で検索しても、ヒットするのは・・・
 ・ChartObject
 ・OLEObject
 ・Shape
・・・の三つだけです。
なので、「ShapeRangeオブジェクト」は確実に、「TopLeftCell」プロパティを保持・内包していません。

うまくいかないほうのコードではWithが無ければ、
Set rng = Range(shp.TopLeftCell, shp.BottomRightCell)
という意味になると思いますが、

すこしまとめますと・・・

うまくいくほうでは「変数shp」の中身は「Shapeオブジェクト」。
うまくいかないほうでは「変数shp」の中身は「ShapeRangeオブジェクト」。
そしてヘルプやオブジェクトブラウザによると、
「Shapeオブジェクト」は、「TopLeftCell」プロパティを保持・内包していますが
「ShapeRangeオブジェクト」は「TopLeftCell」プロパティを保持・内包していません。(ついでに、BottomRightCellも保持・内包していません。)

つまり、「ShapeRangeオブジェクト」は「TopLeftCell」プロパティも「BottomRightCell」プロパティも保持・内包していないのにもかかわらず、「変数shp」に代入(Set)してしまったので、そのため、
「shp.TopLeftCell」と書くことで「ShapeRangeオブジェクト.TopLeftCell」と書いたことになってしまい、
また、「shp.BottomRightCell」と書くことで「ShapeRangeオブジェクト.BottomRightCell」と書いたことになってしまったので、
変数「rng 」に代入する直前の段階で、
「いま、変数shpにはShapeRangeオブジェクトが代入されちゃってますが、ShapeRangeオブジェクトには、もともとTopLeftCellもBottomRightCellも内包されていませんよ?」=すなわち、「オブジェクトはこのプロパティ、またはメソッドをサポート(保持・内包)していません」とエラーが出てしまったのではないかと思います。
    • good
    • 0
この回答へのお礼

丁寧にありがとうございます。
この回答のおかげでNo.1さんのおっしゃる意味がわかりました。
大変助かりました。重ねてお礼申し上げます。

お礼日時:2019/04/18 09:55

「必ずShapeRangeを使う必要がある」、というご事情でしたら、No1のご回答をされたかたのご回答通りです。

大変、失礼いたしました。私の回答は無視してください。
その際も、F8実行+ローカルウィンドウで変数shpの中身を調べて頂ければ、より、明確になると思います。
    • good
    • 0
この回答へのお礼

Shaperangeはどうしても外せない、というわけでもなかったので問題ありません。
ありがとうございました。

お礼日時:2019/04/18 09:54

すみません。

訂正です。

「うまくいくほう」も同じくF8キーでステップ実行して
「Set shp = Selection.ShapeRange」の実行直後に



「うまくいかないほう」も同じくF8キーでステップ実行して
「Set shp = Selection.ShapeRange」の実行直後に

でした。すみませんでした。
    • good
    • 0

「うまくいく」のほうの動きから察しますと、



「うまくいかない」のほうの、

事前にオブジェクトを選択してからの
Set shp = Selection.ShapeRange



Set shp = Selection

にするってことではダメなんでしょうか?・・・

単体のシェイプを選んで ×××・・・、みたいな・・・

そういうことがしたいのではなかったでしょうか?

意味が違ってたらすみません。

ローカルウィドウやウォッチ式ウィンドウなどで、オブジェクト変数や式の中身を色々と調べると色々とわかるのではないでしょうか?

ヘルプを読むと、「ShapeRange」オブジェクトは「図形範囲」「使用例:名前またはインデックス番号で指定した図形セットを取得する」ということのようですので、単一の図形も扱えるっぽいですが、どちらかというと複数の図形をいっぺんに扱う的なときに使うっぽい感じに読めました。

でも「うまくいかない」ほうのコードを見ると、、「単一のシェイプを選択して何かしたい」っぽいので、わざわざ、「ShapeRange」オブジェクトを意識しなくてもよいのではないかと思いました。
基本、「Selection」だけで、「1つのシェイプを選択した」というような意味になるので。
セルをクリックしても図形をクリックしても「Selection」と書くだけでよいのだから、それだけで良い(「ShapeRange」の記述は要らない)のではなかしら?と思いました。

意味が違ってたらすみません。
    • good
    • 0
この回答へのお礼

わかりやすい回答ありがとうございました。

shaperangeにTopLeftCellプロパティがないことを見落としていました。
助かりました。

お礼日時:2019/04/18 09:52

>Excel vba Range型変数格納



Shape をRange 型に格納するというのは無理というか、
シート上のRange と、Shape は、セルAddress とは繋がってますが、フェーズ(階層)が違いますから、シート上のRange に、Shape は上に乗っているだけなのです。

その違いをプログラム的にどう説明するというのは、無理なのですが、何を目的にするかによって答えられると思います。

>Sub うまくいく()
>Dim rng As Range, shp As Object
>
>For Each shp In ActiveSheet.Shapes
>With shp
>Set rng = Range(.TopLeftCell, .BottomRightCell)
>Debug.Print rng.Address
>End With
>Next shp
>End Sub

うまくいっているのではなくて、エラーが出ていないだけで、図形を格納しているわけではありません。以下の「オブジェクトで格納する方法」を参照してください
'-----------------------------
Dim ShapeNames() 'プロシージャ外変数
Dim Rngs As New Collection 'プロシージャ外変数
'サブルーチンにする限りは、あまり意味はありません。
'***********
Sub GetShapeNames()
'名前で格納する方法
 Dim shp As Shape
 Dim i As Long
'配列変数を使う意味は得にありません、後で、Split関数で切り分けても可能です。
 ReDim ShapeNames(ActiveSheet.Shapes.Count - 1) '再定義
 For Each shp In ActiveSheet.Shapes
   Debug.Print shp.Name
  ShapeNames(i) = shp.Name
  i = i + 1
 Next
 Call SelectShapes
End Sub
'*
Sub SelectShapes()
ActiveSheet.Shapes.Range(ShapeNames).Select '全部選択
End Sub
'-----------------------------
Sub GetShapeNames2()
'オブジェクトで格納する方法(取り出しは番号)
 Dim shp As Shape
 Dim i As Long

 For Each shp In ActiveSheet.Shapes
  With shp
   i = i + 1
   Rngs.Add Range(.TopLeftCell, .BottomRightCell)
  End With
 Next
 Call SelectShapes2(2) '2番目を選択
End Sub
'*
Sub SelectShapes2(ByVal num As Long)
Dim shp As Shape
For Each shp In ActiveSheet.Shapes
 If Not Intersect(Rngs(num), shp.TopLeftCell) Is Nothing Then
  shp.Select
 End If
Next
End Sub
    • good
    • 0
この回答へのお礼

ご返答ありがとうございました。
ShapeをRange型に格納したかったわけではありませんでした。
vba周辺の習熟不足につき当方の質問のしかたが的確でなかったかと思います。
お手数おかけしました。

お礼日時:2019/04/18 10:02

こんにちは



属性値(TopLeftCellなど)を利用するのですから、対象となるのは単体のShapeオブジェクトでないとうまくいかないはずです。
一方で、ShapeRangeは文字通りshapesのRangeですから、仮に実質的な内容が一つであったとしても、包含オブジェクトであることは変わりません。

単体のShapeを取得するために
 Selection.ShapeRange.Item(1)
とか
 Selection.ShapeRange(1)
を参照するようにすれば、動作するのではないかと思います。
    • good
    • 0
この回答へのお礼

的確なご返答ありがとうございます。
おっしゃる通りです。
記述の問題点を捉えることができ勉強になりました。

お礼日時:2019/04/18 09:57

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!