プロが教える店舗&オフィスのセキュリティ対策術

シート上のフォームなどを表示/非表示するため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

A 回答 (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
    • good
    • 2
この回答へのお礼

非常に丁寧にお教えいただき、ありがとうございました。
自分自身の不勉強を痛感させられます。
これからもご指導のほど、よろしくお願いいます。

お礼日時:2007/02/13 09:20

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
    • good
    • 1
この回答へのお礼

ありがとうございます。
嗚呼、高度すぎてにわかには理解できそうもありませぬぅ。

お礼日時:2007/02/10 17:00

VBE画面のオブジェクトブラウザで見てもらうと分かりますがShapesクラスにはVisibleプロパティはありません。

Shapeクラスにはあります。
ですからtest04ではエラーになりtest05は動作します

DrawingObjectsは互換機能で残されているオブジェクトだったと思います。OFFICE2003だと「非表示の項目も表示する」にしないとオブジェクトブラウザにもでてきません。

DrawingObjectsクラスにはVisibleプロパティがあるから、test06は動作すると考えられます。なお以下は同じことです。
 ActiveSheet.DrawingObjects.Select
 ActiveSheet.Shapes.SelectAll
    • good
    • 0
この回答へのお礼

> VBE画面のオブジェクトブラウザで見てもらうと分かりますがShapesクラスにはVisibleプロパティはありません。Shapeクラスにはあります。

な~るうど・・・。ありがとうございます。
これはオブジェクトブラウザのShapeクラスの右側の「'Shape'のメンバ」の中にvisibleと表示があるけど、Shapesクラスの右側の「'Shapes'のメンバ」の中にvisibleと表示がないからそう判断すればよいということなんですね?

お礼日時:2007/02/10 16:57

小生、分かっていない部分もありますが、少なくとも


Hiddenされた、Shapeをセレクトはできないと思います。
コレクションは、基本的に番号、或いは名称で決めてやらなければいけないと思います。
このルーチンは、トグルスイッチみたいな動きをすればよいと考え
下記のスクリプトを作り、きちんと動くことを確認しました。

Sub test08()
With ActiveSheet.Shapes(1)
.Visible = Not .Visible
End With
End Sub

これであれば、このルーチンを実行する度、shape(1)は、
表示されたり、非表示となったりします。
    • good
    • 0
この回答へのお礼

ありがとうございました。

お礼日時:2007/02/10 16:58

こんにちわ


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
とか
    • good
    • 0
この回答へのお礼

> Shapes.Visible 自体がおかしいからだと思います。

そのようですね、ありがとうございます。
ただ、Selectionでは非表示の場合、Selectできなくなっちゃいます。

お礼日時:2007/02/10 16:46

オートシェイプは、作成順に番号がつけられます。


 シート上にオートシェイプが、1つしかなくても 最初の番号が付与されているとは、限らないのです。
test04の場合は、一つしか 指定していないので、番号が合わずに Errとなるのでしょう。 たまたま 番号が、合ったとしても 別の場面で Errになります。
このことは、マクロの記録⇒オートシェイプを選択⇒記録の終了 
トレース結果(オートシェイプの番号を確認する)で確認出来ます。
test05などは、オートシェイプの数(名前)を検索していますので、Errが出ないのです。
似たようなものに、画像がありますが これも取り込まれたときに名前が、付与されますのでオートシェイプと同じ処理が、必要になります。
    • good
    • 0
この回答へのお礼

さっそくありがとうございます。

そうでしょうか?
たとえばオートシェープの中でも楕円(Oval)だけを選んでやった場合、

Sub test041()
With ActiveSheet.Ovals
If .Visible = False Then
.Visible = True
Else
.Visible = False
End If
End With
End Sub

で、楕円が何個あろうがちゃんと作動するんですが・・・・。

お礼日時:2007/02/10 15:11

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