Excel VBA オブジェクトの指定方法と速度

このQ&Aのポイント
  • Excel VBAにおけるワークシートの指定方法には複数の方法がありますが、速度の順番はどうなるのでしょうか?
  • 変数にオブジェクトを格納して使用する方法の方が速度が速いと言われていますが、具体的な速度比較はどうでしょうか?
  • Excelのオブジェクトに関して詳しい方がいらっしゃいましたら、指定方法と速度について教えてください。
回答を見る
  • ベストアンサー

Excel VBA オブジェクトの指定方法と速度

Excel VBAについて質問です。 ワークシートを指定するときの書き方には色々ありますが、1~3の速度の順番はどうなりますか? オブジェクトは、変数に入れて使用したほうが速度が速くなるそうなので、 1より2のほうが速いと思いますが、3はどうでしょうか? 1.Worksheets("sheet1") 2.Dim ws As Worksheet   Set ws = Worksheets("sheet1") 3.Sheet1 (VBE画面で表示されるシートのプロパティのオブジェクト名) Excelのオブジェクトについて詳しいかたがいらっしゃいましたら教えてください。 よろしくお願いいたします。

  • ii93
  • お礼率92% (26/28)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.3

No.2 です。お礼欄、補足欄、拝見しました。 > しかしなぜかApplication.Run arrProc(i)でエラーが発生して動作させることができませんでした。。 どのようなエラーでしょうか。 | 実行時エラー '1004' | | マクロ 'test0' を実行できません。このブックでマクロが使用できないか、またはすべての | マクロが無効になっている可能性があります。 添付画像で示した実行時エラーでしたら、 複数のモジュールにまたがってプロシージャ名が重複している場合に 簡単に再現されるものです。 対策としては、同一VBProject内に同名のプロシージャ名がないように命名し直すか、 簡単に済ませるなら、 >      Application.Run arrProc(i) に対して、モジュール名を明示するように書き直す方法があります。 仮に、 私が提示したプロシージャすべてが、 [Module3]という標準モジュールに書かれている場合でしたら、       Application.Run "Module3." & arrProc(i) のように、モジュール名の末尾に"."を付加したものを文字列として書き加えれば、 プロシージャの呼び出しが適切に行われるようになります。 エラーに関しては、エラーメッセージの内容によって対応が異なります。 > Sheet1とは一体何なのかを知りたかったのです。 VBProject クラスのメンバーとして、 シートオブジェクトが生成される時に(新規ブック作成時やシート追加時) [Excel Objects](vbext_ct_Document)タイプのVBComponentが追加され 仮の名前を自動的に振られたものが、[Sheet1] になります。 VBComponentの名前については[ThisWorkbook][Module1][UserForm1]などと同等のもので、 自動的に付番されますが、変更可能な名前です。 一般的な記法で   UserForm1.Show 等と同様、CodeModuleに関連付けられたオブジェクトを参照する際にも この名前を「オブジェクト名」として用いることができます。   Sheet1.Select などのように、、、。 VBProject で定義された オブジェクト ≒ クラス としての   Sheet1 です。 VBComponent の名前が、そのままオブジェクト名になります。 > Sheet1もオブジェクト変数なのではないか 習熟の段階に合わせて「円周率は3」のように、 正しくはないけれど、一旦はそういうことにしておいて次の段階に進むことを 優先させるような教え方としては、「Sheet1もオブジェクト変数」という 覚え方でも支障はないような気はします。 実行時に格納される値(オブジェクト)を変更可能なのが変数です。 VBProject で定義された オブジェクト ですので、実行時のアクセスもVBから見れば直接的で単経路になります。 実際的には、プロシージャやモジュールで定義・設定されている変数の方が より単経路になる筈ですから微かにアクセスは速いようですし、 変数に格納した方が、名前の衝突や各種オーバーヘッドを事前に回避する意味があります。 > CodeNameの意味 Worksheet クラス(Chart クラス)の CodeName プロパティです。 VBProject で定義された オブジェクト名=VBComponent名を返します。 以下、引用 |Excel 開発者用リファレンス |Worksheet.CodeName プロパティ |オブジェクトのコード名を返します。値の取得のみ可能です。文字列型 (String) の値を使用します。 |構文 |式.CodeName | |式 Worksheet オブジェクトを返すオブジェクト式を指定します。 | |備考 |コード名は、選択したオブジェクトの [プロパティ] ウィンドウの Name プロパティで確認できます。デザイン時に、このプロパティの値を変更してコード名を変更することができます。実行時に、このプロパティの値をコードで変更することはできません。 |オブジェクトのコード名はオブジェクトを表すオブジェクト式の代わりに使用できます。たとえば、ワークシートのコード名が "Sheet1" である場合、次の式は同じです。 |Worksheets(1).Range("a1") |Sheet1.Range("a1") |シート名とコード名は異なる場合もあります。シートの作成時は、シート名とコード名は同じです。しかし、シート名を変更してもコード名は変更されません。また、Visual Basic Editor の [プロパティ] ウィンドウでコード名を変更してもシート名は変更されません。 |使用例 |次の使用例は、ワークシート 1 のコード名を表示します。 |MsgBox Worksheets(1).CodeName 以上引用。 ヘルプでのここら辺の扱いについては、[コード名]のような用語が統一されていないようなので、 こちらでは積極的に紹介しなかったのですが、 今回のお尋ねについて一通り解説した内容ではあります。 私の説明もうまくないように感じていますが、伝わるものがあるといいです。

ii93
質問者

お礼

お礼が遅くなり申し訳ありません。 エラーの件、恥ずかしながらご指摘の通りで無事動かすことができました。 とても詳しい解説ありがとうございます!! 完全に理解したとは言えませんが、なんとなくわかったような気がします。 VBComponentであるSheet1より、プロシージャやモジュールで定義・設定されている変数wksのほうが単経路で速いのですね。 なぜ後者のほうが単経路になるのかまでは理解できませんでしたが、そういうものだというふうに捉えるべきでしょうか? 私はオブジェクトやクラスについて、まだまだ勉強が足りません。。 ただ動けばよいではなく、きちんとした美しいPGMを書けるようになりたいです!

その他の回答 (3)

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.4

#1です >もしかして3(Sheet1)もオブジェクト変数なのでしょうか。。。? Sheet1はオブジェクトそのものというかインスタンスじゃないのかなと考えて検索してみました。参考URLに深~い話が載っています。 「Sheet1はクラス(雛形)であり、同名のインスタンス(雛形を元に生成したオブジェクト)でもある。Sheet1のシートモジュールにプロシージャを追加できるのは、クラスだから。プロシージャを追加したりすると、インスタンスが再生成されるのでSheet1インスタンスのメモリ上のアドレスが変わる。ユーザーがアクセスするのはクラス名と同名のインスタンスの方である。」 そう言われると、成る程と思えます。文中ではオブジェクト参照としているのを敢えてインスタンスに書き換えてみましたが、このオブジェクト参照というのはオブジェクト変数とは違い、いわゆるオブジェクトと思います。と、言うわけで「オブジェクト変数」では無いと思います。

参考URL:
http://excelappwithvba.web.fc2.com/managing_excel_objects/study_of_excel_objects.html
ii93
質問者

お礼

またまたの回答ありがとうございます!! ご紹介していただいたサイトを読みました。 まさに私が疑問に思っていたことについて書かれていました。 なるほど、変数ではなくオブジェクトそのものということですね! これはつまりNo.3の方のおっしゃっているVBComponentオブジェクトになるのかなと思いました。 Excelは奥が深いですね。まだまだ勉強が足りません。。

回答No.2

こんにちは。 回答書いている間に先着回答がありましたが(ネタカブリもありますが)、 せっかく書いていたのでお邪魔します。 ひとまず直接の回答として、以下のmainプロシージャを実行して、 イミディエイトウィンドウで結果を確認してください。 ' ' /// Option Explicit #If VBA7 Then '   Private Declare PtrSafe Function timeGetTime Lib "winmm.dll" () As Long #Else   Private Declare Function timeGetTime Lib "winmm.dll" () As Long #End If Private wks As Worksheet Private arrTime() As Long Private buf Private Const T As Long = 100000 ' 試行数は適当に Sub main() Dim arrProc() Dim nUB As Long Dim i As Long Dim j As Long   Set wks = Sheets("Sheet1")   arrProc() = VBA.Array("test0", "test1", "test2", "test3", "test4", "test5", "test6")   nUB = UBound(arrProc())   ReDim arrTime(nUB, 0 To 1)   For i = 0 To nUB     arrTime(i, 0) = timeGetTime()     For j = 1 To T       Application.Run arrProc(i)     Next j     arrTime(i, 1) = timeGetTime()   Next i   Set wks = Nothing   For i = 0 To nUB     Debug.Print "test" & i, arrTime(i, 1) - arrTime(i, 0); "milli-Sec."   Next i End Sub Private Sub test0()   buf = wks.Name End Sub Private Sub test1()   buf = Sheets("Sheet1").Name End Sub Private Sub test2()   buf = Worksheets("Sheet1").Name End Sub Private Sub test3()   buf = Sheet1.Name End Sub Private Sub test4() Dim o As Worksheet   Set o = Worksheets("Sheet1")   buf = o.Name End Sub Private Sub test5()   buf = Sheets(1).Name End Sub Private Sub test6()   buf = Worksheets(1).Name End Sub ' ' /// あらためて、ご質問の意図を量りかねる面もあるのですが、 基本的にVBAで"速さ"を語る場合は、 同一のオブジェクトへの参照を繰り返さない、というのが大原則です。 そういった意味からすると、 worksheetオブジェクトへのアクセスタイムが問題になるような場面というのは、 worksheetが数千あるような場合に限られるでしょうし、 そのようなブック仮に作成出来たとしてもマクロ以前にブックが使い物にならないでしょう。 test0で示したように、繰り返し参照するものは変数に格納しておく、 というようなことぐらいしか、 シート参照に関しては大してアドバイス出来るようなコツみたいなものはありません。 Sheet1をリテラルではなく変数で扱う場合でしたら、 私は基本的にSheetsで指定します。 Sheet1 のようにCodeNameでオブジェクトを呼び出せるのなら、 アクセス自体は速いですけれど、 ブックのウィンドウに表示される名前を直接編集できるName、と、 主にVBEプロパティページから変更可能なオブジェクト名としてのCodeName、と、 それぞれが別の名前になることを想定すると、扱い難いですし混乱の種です。 一度しか使わないマクロを短時間で書きたい時ぐらいにしか、 CodeNameでオブジェクトを呼び出すことは(私は)しません。 解答に書く人も滅多に見掛けないですよね。 とりあえず、 worksheetオブジェクトへのアクセスタイムの差というのは無視した方が好いように思います。 変数やWithブロックを使うなどしてアクセス回数を減らすことを重視してあげてください。 或いは、こちらが想定できていないような 差が出る場面がある、ということでしたらば、補足欄にでも書いてみて下さい。

ii93
質問者

お礼

ご回答ありがとうございます! しかしなぜかApplication.Run arrProc(i)でエラーが発生して動作させることができませんでした。。

ii93
質問者

補足

質問の意図としては、3.のSheet1とは一体何なのかを知りたかったのです。CodeNameの意味もよくわかっていません。。 Worksheets("Sheet1")を何度も書くと遅くなるのは、その都度インスタンスが作成されるからではないかと思っていました。変数に入れて使いまわして速くなるのは、インスタンスの作成が1度で済むからですよね? 回答1の方の測定結果から、もしかして3.のSheet1もオブジェクト変数なのではないかと思えてきました。

  • mitarashi
  • ベストアンサー率59% (574/965)
回答No.1

詳しくないので試してみました dim buf as string buf = Worksheets("Sheet1").Name といった操作を100万回やらせてみました。(Win7Home-64bit,xl2010-32bit,Core-i5 3.2GHz) 1. Worksheets("Sheet1").Name 3.042秒 2. ws.Name          0.107秒 3. Sheet1.Name        0.110秒 実行の最初の数回は捨て、5回の測定値の平均です。 Worksheets("Sheet1")は結構遅いのに驚きました。 2と3は最初dim buf as variantでやったときは殆ど一緒でした。 ご参考まで。 試験したコードは下記の通りです。既に出典は分かりません。 '高分解能パフォーマンスカウンタ用API Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long Sub test() Dim curStartTime As Currency Dim curEndTime As Currency Dim curFreq As Currency Dim ws As Worksheet Dim buf As String Dim i As Long '高分解能パフォーマンスカウンタの周波数を取得 If QueryPerformanceFrequency(curFreq) = 0 Then MsgBox "ハードウェアが高分解能パフォーマンスカウンタをサポートしていません!", vbCritical Exit Sub End If Set ws = Worksheets("Sheet1") '開始時刻を取得 Call QueryPerformanceCounter(curStartTime) For i = 1 To 1000000 buf = Worksheets("Sheet1").Name ' buf = Sheet1.Name ' buf = ws.Name Next i '終了時刻を取得 Call QueryPerformanceCounter(curEndTime) '結果の表示 Debug.Print (curEndTime - curStartTime) / curFreq End Sub

ii93
質問者

お礼

ご回答ありがとうございます! 2と3は変わらないのですね! 2はオブジェクト変数ですが、もしかして3もオブジェクト変数なのでしょうか。。。?

関連するQ&A

  • Excel VBA 定数にオブジェクトを指定したい

    Excel VBA 定数にオブジェクトを指定したい いつもお世話になりますm(__)m Excel VBAで、定数としてオブジェクトの指定はできないのでしょうか? 例えば、WorkSheets("Sheet1")を定数「Srt1」として設定したいのですが、  Public Const Srt1 As Object = Worksheets("Sheet1") としても「定数のデータ型が不正です」とエラーがでます。 例えば、セルに値をセットする時に Worksheets("Sheet1").Range("A1").Value="あああ" Worksheets("Sheet1").Range("A2").Value="いいい" Worksheets("Sheet1").Range("A3").Value="ううう" と書きますが、これを Srt1.Range("A1").Value="あああ" Srt1.Range("A2").Value="いいい" Srt1.Range("A3").Value="ううう" と書ければプログラムも見やすく、書きやすくなると思いました。 プログラムの最初に Dim Srt1 As Object Set Srt1 = Worksheets("Sheet1") とすれば使えるのですが、複数のシート名をまずは定数として登録したいと思っていますが、オブジェクト(ワークシート名)は定数として登録することは出来ないのでしょうか? お詳しいかた、是非ともご教授お願い致しますm(__)m

  • エクセルVBAでFor each文

    下記のようなコードを書きたいのですが「オブジェクトが必要です」というエラーが 出力されてしまいできないようです。何か代替案はありますでしょうか。 --- dim ws as worksheet with thisworkbook for each ws in array(.worksheets(1),.worksheets(2),.worksheets(3)) with ws 'ここに処理を書く end with next ws end with --- ちなみにこのbookにある全てワークシートで処理を回したいわけではなく 特定のシートのみで処理をしたいです。 エクセル2003です。 よろしくお願いします。

  • エクセルVBE実行時のエラーの意味とその対処方法

    Windows Vistaでエクセル2007を使用しています。 添付の画像のエクセルファイルのVBEに 本文最後のコードを記述して実行させようとすると 下記のようなエラーが出ます。 (実行内容はsheet1の表の内容を sheet2で円グラフとして作成することです) 『実行時エラー'91' オブジェクト変数またはWithブロック変数が設定されてません』 ○質問 1.上記のメッセージの意味を教えてください 2.デバックすると10行目の 『Set Grp1 = WS2.ChartObjects.Add(50, 50, 320, 200)』 がデバックされます。この記述のどこがおかしかったのでしょうか? エクセルVBAにお詳しい方、何とぞご教示お願いします。 なお、コードの内容は以下の通りです。 Sub グラフ作成() Dim WS1 As Worksheet Dim WS2 As Worksheet Dim Grp1 As ChartObject Set WS = Worksheets("sheet1") Set WS = Worksheets("sheet2") Set Grp1 = WS2.ChartObjects.Add(50, 50, 320, 200) Grp1.Chart.ChartType = xl3DPieExploded Grp1.Chart.SetSourceData Source:=WS1.Range("C3:D14"), PlotBy:=xlColumns Worksheets("sheet2").Activate Set WS1 = Nothing Set WS2 = Nothing Set Grp1 = Nothing End Sub

  • EXCEL VBAでworksheetに変数を使って指定は出来ますか?

    EXCEL VBAでworksheetに変数を使って指定は出来ますか? たくさんのワークシートに処理結果を出したいのですが。

  • エクセルのVBAの記述について

    VBAの記述についてなのですが、 Sub filter() Dim gyo As Long Dim ws1 As Worksheet Dim ws2 As Worksheet Dim ws3 As Worksheet Set ws1 = Worksheets("データ") Set ws2 = Worksheets("チーム") Application.ScreenUpdating = False ws2.Range("A4:BH30").Clear gyo = ws1.Range("A65536").End(xlUp).Row ws1.Activate With ws1.Range(Cells(4, 1), Cells(gyo, 6)) .AutoFilter Field:=1, Criteria1:="A" .SpecialCells(xlCellTypeVisible).Copy ws2.Range("A4") Selection.AutoFilter End With Application.ScreenUpdating = True End Sub ならプログラムははしるのですが、 14行目を .SpecialCells(xlCellTypeVisible).Copy ws2.Range(Cells(4, 1)) だと 「実行時エラー 1004 Rangeメソッドは失敗しました Worksheet オブジェクト」 とでるのですが、出来ないのでしょうか? Cells(4, 1)の1のところを変数にして変えていきたいのですが、よい方法はありますか。 よろしくお願いいたします。

  • 【Excel VBA】 WorksheetやRangeオブジェクトとして宣言した変数の開放は必要でしょうか?

    こんばんは。 プロシージャレベルで宣言したWorksheetやRangeなどのオブジェクト変数に対し、 プロシージャを終了する直前に、 Set ○=Nothing を実行して、変数(オブジェクトへの参照)を開放する処理を習慣的行っていました。 これは、絶対に必要な処理なのでしょうか? 開放しないことで不具合が出るケースとはどういう場合なのでしょうか? どなたか、ご教示いただけないでしょうか。 よろしくお願いいたします。 <例> Sub test()   Dim Ws1 As Worksheet      Set Ws1 = Worksheets("Sheet1")   '処理内容      Set Ws1 = Nothing End Sub 尚、CreateObject関数で作成したオブジェクトへの参照などではなく、 あくまでもWorksheetやRangeなどの話です。

  • VBA Worksheetsはプロパティなの?

    (株)C&R研究所発行 Excel VBA逆引きハンドブック 著者 蒲生睦男 234ページを引用します。 ----- ワークシートを参照するには「Worksheets」プロパティを使います。「Worksheets」プロパティは、指定されたブックのすべてのワークシートを表す「Sheets」コレクションを返します。 ----- 私は今までWorksheetsはコレクションだと思ってました。つまりワークシートの集合であると。違うのですか?さらにプロパティはオブジェクトの性質を表わすもので、例えばCellのプロパティであればValue, Colour等です。では、Worksheetsは何のプロパティなのでしょうか?Workbookのプロパティですか?もしそうなら、他にはどんなプロパティがあるのですか?さらに上記引用で「返す」とありますが、返すってなんですか?ファンクションプロシージャの戻り値を返す、みたいな表現はありますがここでの「返す」の意味がよくわかりません。 私の現状認識は以下のものです。どこか誤ってますか? Worksheetsはワークシートの集合体つまりコレクションであり、ワークシートオブジェクトでもある。オブジェクトであるので、性質を表わすプロパティではない。 VBAの構文で Workbook.Worksheet.Range のような表現はよく使いますが、ひょっとして後ろにくっつくのは全部プロパティなのですか?ちょっとよくわかりません。

  • エクセルVBAについて

    こんばんは。エクセルVBAについてアドバイスをお願いします。 エクセルのシートをNotesにオブジェクトとして貼り付けて使用しています。 エクセルファイルを開いたときに「シートA」を表示させましてその後そのシート上のデータを参照しながら別のシート上で作業したいと思っています。 しかしファイルを開くと 「'Sheets'メソッドは失敗しました'Globalオブジェクト'」というメッセージが表示されてしまいます。 エラーがでた場所は下記の※印の場所です。 =============================================== Dim WORK As Long Dim DATA As Object Set DATA = Worksheets("シートA").Range("A1") ※ WORK = DATA.Value =============================================== 情報が足りない場合は追記お願いします。 アドバイスお願い致します。

  • ExcelのVBAについて(勉強中のです。)

    ExcelのVBAについて(勉強中のです。) ここからコード3以降に入力したコードを抜き出してデータ表を作成しそれを保存するコードを作成したいです。例えばCSV形式にするとか? データ表は1日分の表示で、保存して週間や月間または統計データまでを視野にいれています。今回は保存する所です。。 利用しやすい状態と保存形式で、よろしくお願いします。データは生活記録みたいなものです。何したどうしたどうなった? ※大分分岐する予定で、作成中であり、今回はコードの整理は不要です。 '///Sheet1/// Private Sub Worksheet_Change(ByVal Target As Excel.Range) Dim time7 As Range For Each time7 In Target If time7.Column = 1 Then time7.Offset(0, 4).Value = Format(Now, "Short Time") & vbCrLf & _ Format(Now, "yyyy/mm/dd hh:nn:ss AM/PM") End If Application.EnableEvents = False Application.EnableEvents = True Next time7 '(1)シートを変数にセット Dim ws1 As Worksheet Dim ws2 As Worksheet Set ws1 = Worksheets("Sheet1") Set ws2 = Worksheets("Sheet2") '(2)シートを指定してデータを転記 ws2.Range("A3:H3").Value = ws1.Range("A3:H3 ").Value End Sub Private Sub Worksheet_Activate() ' ' 新規行挿入 ' ' Worksheets("Sheet2").Range("3:3").Insert Sheets("Sheet1").Range("H3").Select ActiveCell.FormulaR1C1 = "5" Sheets("Sheet1").Range("E3").Select Selection.ClearContents Dim str_Left As String 'セルE4に文字列、セルH4に数字を予め入れておくこと。 str_Left = Left(Cells(4, 5), Cells(4, 8)) MsgBox str_Left & vbCrLf & " " & "OKボタンを押してください!" Sheets("Sheet1").Range("A3").Select Dim se_r As String se_r = Application.InputBox("バーコードを入力してください") Select Case se_r Case "False" MsgBox "キャンセルされました" Case "" MsgBox "空欄が入力されました" Case Else Range("A3").Value = se_r End Select End Sub ' ///Sheet2/// Private Sub Worksheet_Activate() Dim Emp(1 To 300) As String Dim msg As String Dim i, i2, Cnt As Integer Dim N_In As Variant For i = 3 To 3 If IsEmpty(Cells(i, 1).Value) = False Then 'ここで空欄判定 Worksheets("Sheet1").Range("3:3").Insert '対象セルアドレスを改行処理 End If Next i '(1)シートを変数にセット Dim ws1 As Worksheet Dim ws2 As Worksheet Set ws1 = Worksheets("Sheet1") Set ws2 = Worksheets("Sheet2") ws1.Activate End Sub

  • VBA オブジェクト型使用の利点は?

    例えばワークシートの表現を考えます。 自分は今まで以下のようにしてました。 Dim sheet1 As String sheet1=Worksheets(1).Name Worksheets(sheet1).Activate オブジェクト型宣言を用いて以下のように書き換えられます。 Dim sheet1 As object set sheet1=Worksheets(1) sheet1.Activate ソースコードとしてはスッキリしますが、見た目以外でどのようなメリットがあるのですか?

専門家に質問してみよう