- ベストアンサー
エクセルVBAでShapesまたはDrawingObjects
シート上のフォームなどを表示/非表示するためtest04を書きましたが、「実行時エラー438 オブジェクトはこのプロパティまたはメッソッドをサポートしていません」となります。 しかし、Test05のように同じことをForNextで回せばうまくいきます。 また、Test06のようにShapesをDrawingObjectsに書き換えただけでもうまくいきます。 では、Test04がエラーになるのはなぜでしょうか? Sub test04() With ActiveSheet.Shapes If .Visible = False Then .Visible = True Else .Visible = False End If End With End Sub Sub test05() For Each sp In ActiveSheet.Shapes If sp.Visible = False Then sp.Visible = True Else sp.Visible = False End If Next End Sub Sub test06() With ActiveSheet.DrawingObjects If .Visible = False Then .Visible = True Else .Visible = False End If End With End Sub
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは。 私の書く話は分かってもらえるか分かりませんが……。(長ったらしく書くからいけないのでしょうけれども)理屈ではなくて、こういうことは、実践に尽きると思います。 merlionXX さんの #1 のお礼の中で書いた考え方は実務上では、私は正解だと思いますよ。ただ、それを、どのように実現出来るかによります。出来ない場合も想定はしておかないといけないわけです(^^; コレクションをばらして、それにプロパティを与えればよい、っていうのは、それはその通りなのですが、問題は、Shapes というものにあるのではないでしょうか?もともと、Shapes は、いくつかのオブジェクトの総称、つまりコレクション(Collection)ですね。確かに、Collection の場合は、分化させないと、うまく処理できません。Index で切り分けるのは良いとは思います。 しかし、昔のバージョンでは、こういう集合(Collection)ではなかったはずです。たとえば、test06 のプロシージャは、古い書き方なんですよね。だから、コードは通るはずです。インテリセンスを無視して書いているはずです。しかし、test05 の場合は、論理的には正しくても、実際上は、コレクションのそれぞれを全部を通すのはありえませんね。 >シート上のフォームなどを表示/非表示するためtest04を書きましたが、 ということで、本来、Shapes コレクションの中で、ここには、登場していないOLEObjects を持ち出すと、余計に話がややこしくなってしまいます。早い話、モノ(Object)は何か、に尽きるのではないでしょうか?モノをどう特定化するかで、それが出来れば、半分以上は終わったようなものです。 もちろん、Shapes を使ってもかまわないです。それは、その後の問題です。 たぶん、私だったら、オブジェクトのフォームが決まっていなければ test07 のようにし、決まっていれば、test08 のようにするでしょうね。しかし、その集合体を扱う場合は、Index や名前では、必ずしも必要はありませんね。オブジェクトのフォームだけではない場合は、Type で選別していくわけです。ただし、必ずしも ShapeRange ではうまくいかない可能性があります。それは、本来、別々のものが一緒になっているからです。 別々のものを別々に直接扱えば、混乱は少ないのですが(例:test9)、そういう方法が、ヘルプなどには出てこないのです。(Ver.5 スタイルかな?この辺り、MSはどう考えているかは分からないけれども、旧バージョンスタイルは廃止の方向にあると考えてよいと思います。そうすると、Shapes コレクションから操作しなければならないわけです。そういう自己矛盾を抱えながら、EXCEL VBAを使っていくわけですが……。) Sub test07() Dim o As Object With ActiveSheet.DrawingObjects For Each o In .ShapeRange If o.Type = msoFormControl Then o.Visible = Not o.Visible End If Next o End With End Sub ボタンとかで決まっていれば、以下のようになりますね。 Sub test08() Dim o As Object For Each o In ActiveSheet.Buttons o.Visible = Not o.Visible Next o End Sub なお、一括だったら、一行でもよいのですが、たったこれだけのことなんです。 Sub test09() With ActiveSheet.Buttons .Visible = Not .Visible End With End Sub
その他の回答 (5)
- Nayuta_X
- ベストアンサー率46% (240/511)
Helpからの抜粋です よ~~く読んで理解してください。 メモ シートのすべての図形に対して同時にプロパティの削除や設定などを実行する場合は、すべての図形を選択し、ShapeRange プロパティでシートのすべての図形を含む ShapeRange コレクションを作成して、そのコレクションに適切なプロパティまたはメソッドを設定します。 単体の Shape オブジェクトを取得するには、Shapes(index) プロパティを使用します。引数 index には、図形の名前またはインデックス番号を指定します。次の使用例は、myDocument の図形 1 に既定の塗りつぶしのグラデーションを設定します。 Set myDocument = Worksheets(1) myDocument.Shapes(1).Fill.PresetGradient _ msoGradientHorizontal, 1, msoGradientBrass Shapes コレクションのサブセットを表す ShapeRange コレクションを取得するには、Shapes.Range(index) プロパティを使用します。引数 index には、図形の名前またはインデックス番号、あるいは複数の図形名またはインデックス番号の配列を指定します。次の使用例は、myDocument の図形 1 および図形 3 に塗りつぶしのパターンを設定します。 Set myDocument = Worksheets(1) myDocument.Shapes.Range(Array(1, 3)).Fill.Patterned _ msoPatternHorizontalBrick 解説 ワークシートの ActiveX コントロールは、2 つの名前を持ちます。シートを表示したときに名前ボックスで確認できる図形の名前、およびプロパティ ウィンドウの Name プロパティでコントロールのコード名を確認できます。最初にワークシートに追加したコントロールでは、図形の名前とコード名が一致しています。しかし、図形の名前、コード名のどちらかを変更しても、もう片方の名前が一致するように自動的に変更されることはありません。 コントロールのイベント プロシージャの場合は、コントロールのコード名を使います。Shapes または OLEObjects コレクションからコントロールを取得する場合は、コード名ではなく、図形の名前を使ってコントロールを指定します。たとえば、コード名および図形の名前が既定の CheckBox1 というチェック ボックスを追加したと仮定します。コントロールの [プロパティ] ウィンドウで Name プロパティを chkFinished と設定してコード名を変更した場合、イベント プロシージャでは必ずコントロールのコード名を使い、Shapes または OLEObject コレクションからコントロールを取得する場合、次のように CheckBox1 を使います。 Private Sub chkFinished_Click() ActiveSheet.OLEObjects("CheckBox1").Object.Value = 1 End Sub
お礼
ありがとうございます。 嗚呼、高度すぎてにわかには理解できそうもありませぬぅ。
- zap35
- ベストアンサー率44% (1383/3079)
VBE画面のオブジェクトブラウザで見てもらうと分かりますがShapesクラスにはVisibleプロパティはありません。Shapeクラスにはあります。 ですからtest04ではエラーになりtest05は動作します DrawingObjectsは互換機能で残されているオブジェクトだったと思います。OFFICE2003だと「非表示の項目も表示する」にしないとオブジェクトブラウザにもでてきません。 DrawingObjectsクラスにはVisibleプロパティがあるから、test06は動作すると考えられます。なお以下は同じことです。 ActiveSheet.DrawingObjects.Select ActiveSheet.Shapes.SelectAll
お礼
> VBE画面のオブジェクトブラウザで見てもらうと分かりますがShapesクラスにはVisibleプロパティはありません。Shapeクラスにはあります。 な~るうど・・・。ありがとうございます。 これはオブジェクトブラウザのShapeクラスの右側の「'Shape'のメンバ」の中にvisibleと表示があるけど、Shapesクラスの右側の「'Shapes'のメンバ」の中にvisibleと表示がないからそう判断すればよいということなんですね?
小生、分かっていない部分もありますが、少なくとも Hiddenされた、Shapeをセレクトはできないと思います。 コレクションは、基本的に番号、或いは名称で決めてやらなければいけないと思います。 このルーチンは、トグルスイッチみたいな動きをすればよいと考え 下記のスクリプトを作り、きちんと動くことを確認しました。 Sub test08() With ActiveSheet.Shapes(1) .Visible = Not .Visible End With End Sub これであれば、このルーチンを実行する度、shape(1)は、 表示されたり、非表示となったりします。
お礼
ありがとうございました。
- Ce_faci
- ベストアンサー率36% (46/127)
こんにちわ Shapes.Visible 自体がおかしいからだと思います。 ActiveSheet.Shapes("Line 1").Visible などになると思います。 Sub test07() ActiveSheet.Shapes.SelectAll With Selection If .Visible = False Then .Visible = True Else .Visible = False End If End With End Sub とか
お礼
> Shapes.Visible 自体がおかしいからだと思います。 そのようですね、ありがとうございます。 ただ、Selectionでは非表示の場合、Selectできなくなっちゃいます。
- Nayuta_X
- ベストアンサー率46% (240/511)
オートシェイプは、作成順に番号がつけられます。 シート上にオートシェイプが、1つしかなくても 最初の番号が付与されているとは、限らないのです。 test04の場合は、一つしか 指定していないので、番号が合わずに Errとなるのでしょう。 たまたま 番号が、合ったとしても 別の場面で Errになります。 このことは、マクロの記録⇒オートシェイプを選択⇒記録の終了 トレース結果(オートシェイプの番号を確認する)で確認出来ます。 test05などは、オートシェイプの数(名前)を検索していますので、Errが出ないのです。 似たようなものに、画像がありますが これも取り込まれたときに名前が、付与されますのでオートシェイプと同じ処理が、必要になります。
お礼
さっそくありがとうございます。 そうでしょうか? たとえばオートシェープの中でも楕円(Oval)だけを選んでやった場合、 Sub test041() With ActiveSheet.Ovals If .Visible = False Then .Visible = True Else .Visible = False End If End With End Sub で、楕円が何個あろうがちゃんと作動するんですが・・・・。
お礼
非常に丁寧にお教えいただき、ありがとうございました。 自分自身の不勉強を痛感させられます。 これからもご指導のほど、よろしくお願いいます。