[[20230704141416]] 『プロパティまたはメソッドをサポートしていません』(やわら) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『プロパティまたはメソッドをサポートしていません』(やわら)

タイトル通りのエラーが出ますが、なぜ出るのか分からずお助けいただきたいです。
ほかのサイト見ても、記述の方法間違ってる部分が分からなくて…
 >wb_moto.ws_moto.Range("M" & i & ":N" & i).PasteSpecial Paste:=xlPasteValues
ここの部分でエラーが出ます。

 Option Explicit

 Sub maxmin()
    Dim fso As Object
    Dim file As Object
    Dim mydir As String
    Dim wb_moto As Object
    Dim ws_moto As Worksheet
    Dim i As Long

    i = 2

    Set fso = CreateObject("Scripting.FileSystemObject")
    mydir = ActiveWorkbook.Path
    Set wb_moto = ThisWorkbook
    Set ws_moto = ActiveSheet

    For Each file In fso.getFolder(mydir).Files
        If fso.getfilename(file.Name) Like Range("A" & i) & "*" Then
            Dim wb As Workbook
            Set wb = Workbooks.Open(Filename:=file, ReadOnly:=False)

            Dim ws As Worksheet
            For Each ws In wb.Worksheets
                If ws.Name Like "*基準値" Then
                    ws.Range("A1").Value = "=MIN(B2:DQ81)"
                    ws.Range("B1").Value = "=MAX(B2:DQ81)"
                    ws.Range("A1:B1").Copy
                    If ws.Name Like "*A*" Then
                        wb_moto.ws_moto.Range("G" & i & ":H" & i).PasteSpecial Paste:=xlPasteValues
                    ElseIf ws.Name Like "*B*" Then
                        wb_moto.ws_moto.Range("I" & i & ":J" & i).PasteSpecial Paste:=xlPasteValues
                    ElseIf ws.Name Like "*C*" Then
                        wb_moto.ws_moto.Range("K" & i & ":L" & i).PasteSpecial Paste:=xlPasteValues
                    Else
                        wb_moto.ws_moto.Range("M" & i & ":N" & i).PasteSpecial Paste:=xlPasteValues
                    End If
                End If
            Next
            'ファイルを閉じる
            wb.Close SaveChanges:=True
        End If
        i = i + 1
    Next
 End Sub

< 使用 Excel:Microsoft365、使用 OS:Windows10 >


 >wb_moto.ws_moto.Range("M" & i & ":N" & i).PasteSpecial Paste:=xlPasteValues
 それは
 ws_moto.Range("M" & i & ":N" & i).PasteSpecial Paste:=xlPasteValues
 で良いと思いますよ。
 ws_motoには、親(book)の情報も持っていますので、ダブルで指定する必要がありません。

 wb_motoというブックは、ws_motoというプロパティは持っていません。

(xyz) 2023/07/04(火) 14:25:44


ありがとうございます。ws_motoだけにしたらいきました。
いろんなサイト見てて、
>Workbooks("貼り付けしたいファイル名").Sheets("貼り付けしたいシート").Range("貼り付けたいセル").PasteSpecial
っていう書き方を紹介されていたのですがこれはファイル名とシート名を直書きで指定するときだけと思えばいいですか?
(やわら) 2023/07/04(火) 14:29:50

 そうですね。
 上記の書き方だとOKです。
 なかなか良い質問で、もっと詳しい説明があると思います。# 出かける予定がありまして。
(xyz) 2023/07/04(火) 14:46:50

ありがとうございます。参考になりました。
察するに、Setしたものはほかに色んな要素(ローカルウィンドウでみられるような)を含むが
直書きだと名前の要素しか持たない、とかそういうことなんですかね?
詳しい説明してくださる方がいたらとても嬉しいです。
(やわら) 2023/07/04(火) 14:59:41

すみません、追加で質問があります。
ステップ実行の時は気づかなかったのですが、
フォルダの中のファイルを一周してもFor Each file In fso.getFolder(mydir).Filesのループが終わりません。
なぜか2行開けてまたループしてしまいます。
原因お判りになりますでしょうか。
(やわら) 2023/07/04(火) 15:27:32

 拙い解説です。
 Workbooks は複数形のsが付いていますよね。
 これはWorkbookコレクションで、Workbookの集まりです。
 ("何とかブック") と、インデックスを与えると、
 ブック群の中の何とかブック、と指定しています。

 >Workbooks("貼り付けしたいファイル名").Sheets("貼り付けしたいシート").Range("貼り付けたいセル")

 ↑は、
 数あるブックの中の"貼り付けしたいファイル名"ブックの、
 数あるシートの中の"貼り付けしたいシート"シートの、
 数あるセルのなかの"貼り付けたいセル"範囲のセル
 となります。

 こちらを一読すれば、イメージは出来るかと。
 https://vba-beginner.com/vba2-7-4009/

(tkit) 2023/07/04(火) 15:34:52


xyzさんの
>wb_motoというブックは、ws_motoというプロパティは持っていません。
に便乗して、じゃあどんなプロパティまたはメソッドならサポートしている(持っている)と判断できるのかというと、
wb_moto.Sheets()
とか、
wb_moto.Worksheets()
とか。
wb_moto. と変数名をピリオドまで入力した時に、予測変換のごとく出てくる文字列(インテリセンス、と呼ぶ)は「サポートしている」。

>fso.getFolder(mydir).Filesのループが終わりません。
プログラム見てないけど、そりゃ典型的な「無限ループ」ってやつかと。
どうなったら終わっていいのか(終了条件、と呼ぶ)を設定してあげよう。
(ufj) 2023/07/04(火) 15:56:01


お二人ともありがとうございます。
どちらの説明もわかりやすかったです。少し理解が進みました。

無限ループについてですが、
>For Each f In fso.GetFolder(mydir).Files
この記述の意味を「FSOで取得したフォルダの中にあるファイルの数分ループする」だと思っていたので
無限ループしないはずと思って書いていました。
ループしている以上認識が違うのだと思いますが、調べた範囲だと同じような書き方をしているものしか見つけられませんでした。
何が違うのかを教えていただきたいです。
(やわら) 2023/07/04(火) 16:06:48


 同じファイルが取得していますか?

 Debug.Print f.Path  で、
 イミディエイトに出力して確認してください。

 ファイルが全て取得したのに、ループが止まらない
 のであれば、隠しファイルも取得するので、それかも。

 無限ループなのであれば、提示のコードとは何かが違うかと。
(tkit) 2023/07/04(火) 16:18:21

見てみましたが、同じファイルを再度取得しています。
上のものから少しいじりましたが、根幹部分は変えていないつもりでした。
一応再掲します。

 Sub maxmin()
    Dim fso As Object
    Dim f As Object
    Dim mydir As String
    Dim wb_moto As Object
    Dim ws_moto As Worksheet
    Dim i As Long

    i = 3

    Set fso = CreateObject("Scripting.FileSystemObject")
    mydir = ThisWorkbook.Path
    Set wb_moto = ThisWorkbook
    Set ws_moto = ActiveSheet

    Range("A:A").Clear

    For Each f In fso.GetFolder(mydir).Files
        If LCase(fso.GetExtensionName(f.Name)) = "xlsx" Then
            Dim wb As Workbook
            Set wb = Workbooks.Open(Filename:=f, ReadOnly:=False)
            ws_moto.Range("A" & i) = wb.Name

            Dim ws As Worksheet
            For Each ws In wb.Worksheets
                If ws.Name Like "*基準値" Then
                    ws.Range("A1").Value = "=MIN(B2:DQ81)"
                    ws.Range("B1").Value = "=MAX(B2:DQ81)"
                    ws.Range("A1:B1").Copy
                    If ws.Name Like "*A*" Then
                        ws_moto.Range("G" & i & ":H" & i).PasteSpecial Paste:=xlPasteValues
                    ElseIf ws.Name Like "*B*" Then
                        ws_moto.Range("I" & i & ":J" & i).PasteSpecial Paste:=xlPasteValues
                    ElseIf ws.Name Like "*C*" Then
                        ws_moto.Range("K" & i & ":L" & i).PasteSpecial Paste:=xlPasteValues
                    Else
                        ws_moto.Range("M" & i & ":N" & i).PasteSpecial Paste:=xlPasteValues
                    End If
                End If
            Next ws
            'ファイルを閉じる
            wb.Close SaveChanges:=True
        End If
        i = i + 1
    Next f
    Set fso = Nothing
 End Sub
(やわら) 2023/07/04(火) 16:34:53

 前半部分だけですが、コメントしておきます。
 既に適切なコメントをいただいていますが、念のため。
 (1)
 Set wb_moto = ThisWorkbook
 Set ws_moto = ActiveSheet
    (なお、これはActivWorkbookのActivesheetという意味。
     ThisWorkbookがActiveになっているんだろうけど、そうでない場合もありうるので要注意)
 変数を指定するとき、ws_motoの親であるBookは明確に決まっています。

 実際、ステップ実行して、"ローカルウインドウ"で ws_motoのプロパティを見てください。
 Parentプロパティというものがあり、親のBookが一意に決まっていることがわかります。

 したがって、ws_motoと書けば、どのブックのシートかということは"織り込みずみ"であり、
 「ブックは指定する必要がない」というのが第一のポイントです。

 (2)
 wb_moto.ws_moto と書けば、ブック - シートという階層構造に則っているから問題ないだろう、
 と考えるかもしれませんが、それはws_motoの中身を貴方が知っているからです。
 構文解析上、ws_motoを(Activesheetといった)シート情報に読み替えて、
 という操作を行えば、それは可能ですが、そういう作りにはなっていない(と想像される)。
 つまりは、VBAの作者が構文解析の仕組みをそのように決めており、
 そういうことはできない、ということです。 これが第二の理由です。
 (3)
 wb_motoは、ws_motoという変数をプロパティに持ってはいない、は既に書きました。

(xyz) 2023/07/04(火) 17:09:54


 >なぜか2行開けてまたループしてしまいます。
 2行の空白行は、そのフォルダに拡張子がxlsxではないファイルが2つあるんでしょうね
 すくなくともこのマクロが記述されたファイル(.xlsm) ともう一つなにか

 ローカルディスクにテスト用のフォルダ作って実行したら同じようになりますか? 
(´・ω・`) 2023/07/04(火) 18:31:00

xyzさん、ありがとうございます。
>ThisWorkbookがActiveになっているんだろうけど、そうでない場合もありうるので要注意)
そうでない場合、は他のブックアクティブ状態でVBEから起動した場合などですかね?
ローカルウィンドウのParentプロパティってそういう意味だったことを初めて知りました。
ローカルウィンドウ内の情報、オブジェクト系は多いのであまり理解していないです。

(´・ω・`)さんもありがとうございます。
xlsmと、実行中の一時ファイルがいるので多分それです。
テストフォルダだと正常に完了しました。
元々作業していた場所がSSD上だったから問題が起きていたのかもしれません…?
(やわら) 2023/07/05(水) 12:22:39


 >テストフォルダだと正常に完了しました。
 ということは、コードの問題ではなく、フォルダの方に問題があるようですね

 ネットワークのフォルダなのかなと思ったのですが、
 >元々作業していた場所がSSD
 SSDでもHDDでも違いはないと思いますが、不思議ですね
(´・ω・`) 2023/07/05(水) 14:44:33

 かきわすれ
 i = i + 1
 はIFブロックの中に入れて、書き込みしたときだけ行が進むようにした方がいいと思います
(´・ω・`) 2023/07/05(水) 14:46:11

 外付けだからダメなのかな〜とは思いました。
 ネットワーク上NGはあり得そうなので、リモートデスクトップ接続が原因?とも思いましたが
 Dドライブ直下だとうまくいったので…

 i=i+1については確かにその通りですね(というかそのせいで空白行ができていたわけですね)
 重ね重ねありがとうございます。
(やわら) 2023/07/05(水) 15:55:12

もう見ていないと思いますが投稿しておきます。
 もし、見ているようでしたら、さんと被る部分がありますがご容赦を。

■1
Excelの場合、各オブジェクトの関係性は↓のような構造になっています。

 Application(Excel)
 └Workbookオブジェクト((開いている)ブック)
  └WorkSheetオブジェクト(ワークシート)
   └Rangeオブジェクト(セル)

したがって、【セル】を示すには上記の構造どおりに【どのブック】の【どのシート】の【どのセル】というように示す必要があります。
他方で↓をちょっと真面目に書くと

 Set wb_moto = ThisWorkbook
 Set ws_moto = ActiveSheet

↓のようになります。

 Set wb_moto = ThisWorkbook
 Set ws_moto = ActiveWorkbook.ActiveSheet

これを↓に当てはめて展開してみるとわかると思いますが

 wb_moto.ws_moto.Range(〜)
   ↓のように解釈されている
 ThisWorkbook.ActiveWorkbook.ActiveSheet.Range(〜)
 ~~~~~↑~~~~~ ~~~~~↑~~~~~~~
    ブック        ブック

【ブックのブック】というようにブックを2重に指定してしまっていたために、そんな構造のものは無いってエラーが出てたわけです。

 ThisWorkbook.Worksheets("hoge").Range("A1")
 Workbooks("hoge.xlsx").Worksheets(1).Cells(1,1)

なので↑のように、関係性をまちがっていなければ問題ないので【○○名を直書きで指定】とか【Setすればよい】とかそういう話ではありません。

■2

 ws.Range("A1:B1").Copy
 ws_moto.Range("G" & i & ":H" & i).PasteSpecial

↑のように表現されていますが、PasteSpecialメソッドは左上のセルのみ指定すれば、コピーした範囲に合わせて拡張してくれますから↓のような表現でもOKです

 ws.Range("A1:B1").Copy
 ws_moto.Range("G" & i).PasteSpecial

さらに言うと、Cellsプロパティを使って↓のように表現しても同じ意味になります。

 ws_moto.Cells(i,"G").PasteSpecial

■3

 wb.Close SaveChanges:=True

関連して↑の処理をしていますが、そうなると↓もマストな処理ということでしょうか?

 ws.Range("A1").Value = "=MIN(B2:DQ81)"
 ws.Range("B1").Value = "=MAX(B2:DQ81)"

値貼り付けのためだけに書き込んで計算させているだけであれば、直接コード上で計算させてもよいかなと思います。

 ※なお、問題があるわけではありませんが数式を書き込むなら「Valueプロパティ」ではなく
  「Formula」プロパティのほうが本筋かなという感想です。(好みの問題でしょうが)

■4
こちらも好みの問題ですが、「If〜ElseIf〜Else〜 End If」の部分について、今回のようなケースでは「Select Case」で分岐させるというのも有効だとおもいます。

■5
また、なんとかなっているかもしれませんが↓のようにループの中で変数の宣言をするのはお勧めできません。
冒頭で宣言するか、ループの直前(外側)で宣言するようにするとよいと思います。

    For Each f In fso.GetFolder(mydir).Files
        Dim wb As Workbook
        Dim ws As Worksheet
    Next f

■6
ということを踏まえて以下のようなアプローチもあったかと思います。

 ※1 完成品のプレゼントを意図したものでありません。興味があればステップ実行して研究の上、
    必要な部分のみご自身のコードに組み込んでください。

 ※2 「■3」でも述べましたが、データ元になるシートに数式を書き込む必要がなければ、
    まとめシート?に書き込むだけの話かと思いますのでそちらの例として提示します。

    Sub 研究用()
        Dim MyFile As Object
        Dim dstSH As Worksheet
        Dim wb As Workbook, ws As Worksheet
        Dim 出力行 As Long
        Dim 列 As String
        Dim フラグ As Boolean

        Stop 'ブレークポイントの代わり

        Worksheets.Add after:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)
        Set dstSH = ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)
        dstSH.Name = Format(Now, "MMDD_hhmm")

        出力行 = 3
        For Each MyFile In CreateObject("Scripting.FileSystemObject").GetFolder(ThisWorkbook.Path).Files
            If MyFile.Type = "Microsoft Excel ワークシート" Then
                フラグ = False
                Set wb = Workbooks.Open(Filename:=MyFile.Path, ReadOnly:=False)
                For Each ws In wb.Worksheets
                    dstSH.Cells(出力行, "A").Value = wb.Name

                    If ws.Name Like "*基準値" Then
                        フラグ = True
                        Select Case True
                            Case ws.Name Like "*A*": 列 = "G"
                            Case ws.Name Like "*B*": 列 = "I"
                            Case ws.Name Like "*C*": 列 = "K"
                            Case Else: 列 = "M"
                        End Select

                        dstSH.Cells(出力行, 列).Offset(, 0).Value = WorksheetFunction.Min(ws.Range("B2:DQ81"))
                        dstSH.Cells(出力行, 列).Offset(, 1).Value = WorksheetFunction.Max(ws.Range("B2:DQ81"))
                    End If
                Next ws

                If フラグ = False Then
                    dstSH.Cells(出力行, "A").Value = "【該当なし】" & dstSH.Cells(出力行, "A").Value
                End If
                wb.Close False
                出力行 = 出力行 + 1
            End If
        Next MyFile
     End Sub

(もこな2) 2023/07/18(火) 07:55:44


もこな2さん、ありがとうございます。
とても丁寧な解説ありがとうございます。
知らなかったり、知ってたけど活用できてない内容ばかりでとても勉強になりました。

>値貼り付けのためだけに書き込んで計算させているだけであれば〜
ここは特に仕様があるわけではなく、直接書き込むか悩んだのですが
他の人の作業のお手伝いだったので作業の痕跡を残しておいたほうが疑われないかなと思ってこうしました。
(やわら) 2023/07/25(火) 11:25:36


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.