Excel VBAでの選択の使用を回避する方法


537

私は.SelectExcel VBA で使用することの理解できる嫌悪について多くを聞きましたが、それを使用しないようにする方法がわかりません。Select関数の代わりに変数を使用できれば、コードがより再利用可能になることがわかりました。ただし、をActiveCell使用していない場合(など)の参照方法がわかりませんSelect

私は範囲に関するこの記事、selectを使用しないことの利点に関するこの例を見つけましたが、方法について何も見つかりません


14
Selectおよび/またはActiveSheetなどを使用することが完全に避けられない場合があることに注意することが重要です。ここでの例では、私が見つけたということだ:stackoverflow.com/questions/22796286/...
リックはモニカサポートして

9
そして、アクティブ化または選択が必要な場合-基になるExcelファイルが1つであるpptでグラフデータを編集する-場合があります。
brettdj 14

@brettdj- 最近の例です。ブック内のすべてのシートを同じ値に設定するに.Select / .Selectionは、必要なようです。
BruceWayne

回答:


565

選択を回避する方法のいくつかの例

Dim'd変数を使用する

Dim rng as Range

Set必要な範囲への変数。単一セル範囲を参照するには多くの方法があります

Set rng = Range("A1")
Set rng = Cells(1,1)
Set rng = Range("NamedRange")

またはマルチセル範囲

Set rng = Range("A1:B10")
Set rng = Range("A1", "B10")
Set rng = Range(Cells(1,1), Cells(10,2))
Set rng = Range("AnotherNamedRange")
Set rng = Range("A1").Resize(10,2)

あなたは可能にショートカットを使用Evaluateする方法が、これはあまり効率的であると一般的に生産コードでは避けるべきです。

Set rng = [A1]
Set rng = [A1:B10]

上記の例はすべて、アクティブシートのセルを参照しています。特にアクティブシートのみで作業するWorksheet場合を除き、変数も暗くすることをお勧めします

Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = ws.Cells(1,1)
With ws
    Set rng = .Range(.Cells(1,1), .Cells(2,10))
End With

を使用する場合は、明確にするために明示的にすることをお勧めますActiveSheet。ただし、一部のWorksheet方法ではアクティブシートが変更されるため、注意してください。

Set rng = ActiveSheet.Range("A1")

繰り返しますが、これはアクティブなワークブックを指します。具体的には、ActiveWorkbookまたはのみを使用したい場合ThisWorkbookを除き、Workbook変数を暗くすることをお勧めします。

Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")

を使用する場合は、明確にするために明示的にすることをお勧めますActiveWorkbook。しかし、多くのWorkBook方法がアクティブな本を変更するので、注意してください。

Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")

ThisWorkbookオブジェクトを使用して、実行中のコードを含む本を参照することもできます。

Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")

一般的な(悪い)コードは、本を開いてデータを取得し、再度閉じることです。

これは悪いです:

Sub foo()
    Dim v as Variant
    Workbooks("Book1.xlsx").Sheets(1).Range("A1").Clear
    Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = ActiveWorkbook.Sheets(1).Range("A1").Value
    Workbooks("SomeAlreadyOpenBook.xlsx").Activate
    ActiveWorkbook.Sheets("SomeSheet").Range("A1").Value = v
    Workbooks(2).Activate
    ActiveWorkbook.Close()
End Sub

そして、より良いでしょう:

Sub foo()
    Dim v as Variant
    Dim wb1 as Workbook
    Dim  wb2 as Workbook
    Set wb1 = Workbooks("SomeAlreadyOpenBook.xlsx")
    Set wb2 = Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
    v = wb2.Sheets("SomeSheet").Range("A1").Value
    wb1.Sheets("SomeOtherSheet").Range("A1").Value = v
    wb2.Close()
End Sub

範囲変数としてSubsとFunctionsに範囲を渡します

Sub ClearRange(r as Range)
    r.ClearContents
    '....
End Sub

Sub MyMacro()
    Dim rng as Range
    Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:B10")
    ClearRange rng
End Sub

また、メソッド(FindおよびなどCopy)を変数に適用する必要があります。

Dim rng1 As Range
Dim rng2 As Range
Set rng1 = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10")
Set rng2 = ThisWorkbook.Worksheets("SomeSheet").Range("B1:B10")
rng1.Copy rng2

セルの範囲をループしている場合、最初に範囲の値をバリアント配列にコピーし、それをループする方が良い(速い)ことがよくあります。

Dim dat As Variant
Dim rng As Range
Dim i As Long

Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10000")
dat = rng.Value  ' dat is now array (1 to 10000, 1 to 1)
for i = LBound(dat, 1) to UBound(dat, 1)
    dat(i,1) = dat(i,1) * 10 'or whatever operation you need to perform
next
rng.Value = dat ' put new values back on sheet

これは、何ができるかを知るための小さな味見人です。


7
この見事な答えに加えて、範囲で機能するために、左上を知っている限り、実際のサイズを知る必要はありません ...たとえばrng1(12, 12)、rng1がonlyに設定されていても機能し[A1:A10]ます。
MikeD 2015年

3
@chrisneilsenクリス、省略形のセル参照表記の前にワークシートプレフィックスを使用して、次のRangeように入力する手間を省くことができると思います:ActiveSheet.[a1:a4]またはws.[b6]
ローガンリード

3
@AndrewWillems ...またはこの投稿では48回ですが、誰が数えていますか。☺...しかし真剣に、オブジェクトを保持する変数を操作するときは忘れがちです。variant変数は必要ありませんSet まで、あなたがそれにオブジェクトを割り当てます。たとえば、Dim x: x = 1大丈夫ですが、Dim x: x = Sheets("Sheet1")エラー438が生成されます。ただし、混乱/明確化Dim x: x = Range("A1")するだけではエラーは発生しません。どうして?... オブジェクト自体への参照ではなく、オブジェクトのが変数に割り当てられるためです(それはと同等であるため)Dim x: x = Range("A1").Value
ashleedawg

1
@ user3932000シート名が自動的に変更されるシナリオを知りません。ファイル名に関しては、フォルダ内にその名前のファイルがすでに存在する場合にのみそれを行います。保存...を使用するか、ファイル名をハードコードして文字列として保存します。この問題を解決できない場合は、コメントするのではなく、別の質問をする必要があります。
TylerH 2018

1
@ user3932000それは興味深いQになります。それを処理する方法は確かにあります。古いQでコメントスレッドをハイジャックすることを知るのに十分長い間、あなたは行く方法ではありません
chris neilsen

212

.Select/ .Activate/ Selection/ Activecell/ Activesheet/ Activeworkbookなど...を避けるべき2つの主な理由

  1. それはあなたのコードを遅くします。
  2. これは通常、実行時エラーの主な原因です。

どうすればそれを回避できますか?

1)関連するオブジェクトを直接操作する

このコードを検討してください

Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"

このコードは次のように書くこともできます

With Sheets("Sheet1").Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With

2)必要に応じて、変数を宣言します。上記と同じコードは次のように書くことができます

Dim ws as worksheet

Set ws = Sheets("Sheet1")

With ws.Range("A1")
    .Value = "Blah"
    .NumberFormat = "@"
End With

17
それは良い答えですが、このトピックで見逃しているのは、実際にアクティベートが必要なときです。それは悪いと誰もが言いますが、それを使用することが理にかなっている場合について誰も説明しません。たとえば、2つのワークブックで作業していて、最初にアクティブ化しないと、いずれかのワークブックでマクロを開始できませんでした。少し詳しく説明してもらえますか?また、たとえば、あるシートから別のシートに範囲をコピーするときにシートをアクティブにしない場合、プログラムを実行すると、暗黙的にそれぞれのシートがアクティブになるようです。
user3032689 16

1
データを貼り付けたり、フィルタリングしたりする必要がある場合は、最初にシートをアクティブ化する必要がある場合があります。できるだけアクティブ化しないようにするのが最善ですが、実行する必要がある場合もあります。したがって、上記の答えに従って、アクティブ化と選択を絶対的に最小限にしてください。
Nick

7
重要なのは、それらの使用を完全に回避することではなく、できるだけ多くすることだと思います。ブックを保存して、誰かがそれを開いたときに、特定のシートの特定のセルが選択されるようにするには、そのシートとセルを選択する必要があります。コピー/貼り付けは悪い例です。少なくとも値の場合は、Sheets(2).[C10:D12].Value = Sheets(1).[A1:B3].Value
robotik

1
@Nickシートに貼り付けたり、フィルターしたりするためにシートをアクティブにする必要はありません。貼り付けまたはフィルターコマンドでシートオブジェクトを使用します。練習を通してExcelオブジェクトモデルを学ぶと、より簡単になります。.Activateを使用するのは新しいシートを作成するときだけだと思いますが、コードが完了したときに元のシートを表示したいのです。
phrebh

3
@phrebh .Activate元のシートに移動するために使用する必要はありません。使用するだけですApplication.Goto
GMalc '28

88

上記の優れたすべての回答に私が追加する1つの小さな強調点:

おそらく、Selectの使用を避けるためにできる最大のことは、可能な限り、VBAコードで名前付き範囲(意味のある変数名と組み合わせて)を使用することです。この点は上記で述べましたが、少しおおざっぱです。ただし、特別な注意が必要です。

名前付き範囲を自由に使用するための追加の理由がいくつかありますが、もっと考えられると思います。

名前付き範囲により、コードが読みやすくなり、理解しやすくなります。

例:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")
'e.g, "Months" might be a named range referring to A1:A12

Set MonthlySales = Range("MonthlySales")
'e.g, "Monthly Sales" might be a named range referring to B1:B12

Dim Month As Range
For Each Month in Months
    Debug.Print MonthlySales(Month.Row)
Next Month

それは何という名前の範囲はかなり明白であるMonthsMonthlySales含まれており、手順が何をしていますか。

何でこれが大切ですか?他の人がそれを理解することは簡単ですが、ので、あなたがあなたのコードを参照するか、または使用する唯一の人であっても、あなたはまだ名前付き範囲との良好な変数名を使用する必要があり、部分的にので、あなたが忘れてしまうあなたがそれを行うために何を意味するのか1年後、コードが何をしているかを理解するだけで30分を無駄にします。

名前付き範囲は、スプレッドシートの構成が変更されたときに(そうでない場合は!)マクロが壊れないようにします。

上記の例が次のように記述されている場合を考えてみます。

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1:A12")
Set rng2 = Range("B1:B12")

Dim rng3 As Range
For Each rng3 in rng1 
    Debug.Print rng2(rng3.Row)
Next rng3

このコードは最初は問題なく動作します。つまり、あなたまたは将来のユーザーが「gee wiz、年を含む新しい列を列に追加するつもりだと思いますA!」、または月と月の間に経費列を置くまでです。販売列、または各列にヘッダーを追加します。今、あなたのコードは壊れています。そして、あなたはひどい変数名を使用したので、それを修正する方法を理解するのに、必要以上に時間がかかります。

最初に名前付き範囲を使用していた場合、MonthsおよびSales列は好きなように移動でき、コードは問題なく動作し続けます。


6
名前付き範囲が良いか悪いかのスプレッドシートのデザインについての議論は続いています-私は固執しています。私の経験では、それらはエラーを増やします(コードを必要としない標準ユーザーの場合)。
brettdj


12
私はあなたの開発哲学に同意します。しかし、私はその論文はナンセンスだと思います。範囲名がスプレッドシートをデバッグしている初心者をどのように混乱させることができるかについて話しますが、初心者を使用して複雑なスプレッドシートを見る人は誰でも彼らに値するものを手に入れます!私はかつて財務スプレッドシートをレビューした会社で働いていましたが、それはあなたが初心者に与える種類の仕事ではないことを言うことができます。
DeanOC 2015年

8
意味のある議論はありません。定義された名前に反対する人は誰でも、その影響を完全に理解するのに時間をかけていません。名前付きの数式は、すべてのExcelで単一の最も深くて便利な構成要素になる場合があります。
Excelヒーロー

10
@brettdj:あなたの引用は正しいですが、その後に6つの「Except ...」フレーズが続くことを忘れていました。それらの1つは次のとおりです: " マクロコーディング でのセル参照の代わりとして使用する場合を除くマクロを作成するときは常にセル参照の代わりとしてExcel名を使用してください。これは、追加の行または列の挿入から発生するエラーを回避して、マクロコーディングを行わないようにするためです。目的のソースデータを指します。」
Marcus Mangelsdorf 2017年

47

他の皆が長い答えを与えたので、私は短い答えを与えるつもりです。

マクロを記録して再利用するときはいつでも、.selectと.activateを取得します。セルまたはシートを選択すると、アクティブになります。その時点からRange.Value、アクティブなセルとシートを使用するだけのように、修飾されていない参照を使用するときはいつでも。これは、コードが配置されている場所を監視しない場合や、ユーザーがブックをクリックする場合にも問題になる可能性があります。

したがって、セルを直接参照することで、これらの問題を排除できます。行く:

'create and set a range
Dim Rng As Excel.Range
Set Rng = Workbooks("Book1").Worksheets("Sheet1").Range("A1")
'OR
Set Rng = Workbooks(1).Worksheets(1).Cells(1, 1)

それとも

'Just deal with the cell directly rather than creating a range
'I want to put the string "Hello" in Range A1 of sheet 1
Workbooks("Book1").Worksheets("Sheet1").Range("A1").value = "Hello"
'OR
Workbooks(1).Worksheets(1).Cells(1, 1).value = "Hello"

これらの方法にはさまざまな組み合わせがありますが、それは私のようなせっかちな人にはできるだけ短く表現される一般的な考えです。


33

「...そして、Select関数の代わりに変数を使用できれば、コードがより再利用可能になることを発見しています。」

.Select直接的なセル参照よりも優れた選択となる孤立したほんの少しの状況を考えることはできませんが、避けSelectionなければならないのと同じ理由でそれ.Selectを捨ててはならないという弁護に立ち向かい、指摘します。

いくつかのキーのタップで利用できるホットキーの組み合わせに割り当てられた、短時間で時間を節約するマクロサブルーチンを使用すると、多くの時間を節約できる場合があります。ワークシート全体のデータ形式に準拠していないポケットデータを処理する場合、セルのグループを選択して作業コードを実行できるようにすると、不思議に思います。セルのグループを選択してフォーマットの変更を適用するのと同じように、特別なマクロコードを実行するセルのグループを選択すると、時間を大幅に節約できます。

選択ベースのサブフレームワークの例:

Public Sub Run_on_Selected()
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Selected_Visible()
    'this is better for selected ranges on filtered data or containing hidden rows/columns
    Dim rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each rng In rSEL.SpecialCells(xlCellTypeVisible)
        Debug.Print rng.Address(0, 0)
        'cell-by-cell operational code here
    Next rng
    Set rSEL = Nothing
End Sub

Public Sub Run_on_Discontiguous_Area()
    'this is better for selected ranges of discontiguous areas
    Dim ara As Range, rng As Range, rSEL As Range
    Set rSEL = Selection    'store the current selection in case it changes
    For Each ara In rSEL.Areas
        Debug.Print ara.Address(0, 0)
        'cell group operational code here
        For Each rng In ara.Areas
            Debug.Print rng.Address(0, 0)
            'cell-by-cell operational code here
        Next rng
    Next ara
    Set rSEL = Nothing
End Sub

処理する実際のコードは、1行から複数​​のモジュールまで何でもかまいません。このメソッドを使用して、外部ワークブックのファイル名を含むセルの不規則な選択で長時間実行ルーチンを開始しました。

つまり、およびとSelection密接に関連しているため、破棄しないでください。ワークシートプロパティとしては、他にも多くの目的があります。.SelectActiveCell

(はい、この質問がについて.Selectであったことは知っていますがSelection、初心者VBAプログラマーが推測する可能性がある誤解を取り除きたいと思いました。)


13
Selectionとして明示的に宣言したため、変数に割り当てる前に、オブジェクトのタイプを最初にテストすることもできますRange
L42

29

以下では、Selectアプローチ(OPが避けたいもの)とRangeアプローチ(これが質問への答えです)を比較していることに注意してください。したがって、最初のSelectが表示されたときに読み続けることをお勧めします。

それは本当にあなたが何をしようとしているのかに依存します。とにかく簡単な例が役に立つでしょう。アクティブセルの値を「foo」に設定するとします。ActiveCellを使用して、次のように記述します。

Sub Macro1()
    ActiveCell.Value = "foo"
End Sub

たとえば「B2」など、アクティブなセルではないセルに使用する場合は、最初に次のように選択する必要があります。

Sub Macro2()
    Range("B2").Select
    Macro1
End Sub

範囲を使用すると、任意のセルの値を好きなように設定するために使用できる、より一般的なマクロを作成できます。

Sub SetValue(cellAddress As String, aVal As Variant)
    Range(cellAddress).Value = aVal
End Sub

次に、Macro2を次のように書き換えます。

Sub Macro2()
    SetCellValue "B2", "foo"
End Sub

そしてMacro1は:

Sub Macro1()
    SetValue ActiveCell.Address, "foo"
End Sub

これが少し物事を片付けるのに役立つことを願っています。


1
非常に迅速な対応に感謝します。つまり、通常はセルを範囲に追加し、範囲に名前を付け、それを繰り返し処理する場合、配列を作成するためにすぐにジャンプする必要があるということですか?
BiGXERO

意味がわかりませんが、1つの命令でRangeを作成でき(たとえば、Range( "B5:C14"))、一度に値を設定することもできます(同じにする必要がある場合)範囲内のすべてのセル)、たとえばRange( "B5:C14")。Value = "abc"
Francesco Baruchelli 2012年

29

回避しSelectActivateVBA開発者を少し良くする動きです。一般的に、SelectおよびActivateマクロを記録する場合、したがって、使用されているParentワークシートまたは範囲は常にアクティブ一つと考えられています。

これは回避することができる方法ですSelectActivate、以下の場合には:


新しいワークシートを追加してセルをコピーする:

(マクロレコーダーで生成されたコード)から:

Sub Makro2()
    Range("B2").Select
    Sheets.Add After:=ActiveSheet
    Sheets("Tabelle1").Select
    Sheets("Tabelle1").Name = "NewName"
    ActiveCell.FormulaR1C1 = "12"
    Range("B2").Select
    Selection.Copy
    Range("B3").Select
    ActiveSheet.Paste
    Application.CutCopyMode = False
End Sub

に:

Sub TestMe()
    Dim ws As Worksheet
    Set ws = Worksheets.Add
    With ws
        .Name = "NewName"
        .Range("B2") = 12
        .Range("B2").Copy Destination:=.Range("B3")
    End With
End Sub

ワークシート間で範囲をコピーする場合:

から:

Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste

に:

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")

豪華な名前付き範囲の使用

[]他の方法と比較して、本当に美しいでアクセスできます。自分自身で調べて:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")    
Set MonthlySales = Range("MonthlySales")

Set Months =[Months]
Set MonthlySales = [MonthlySales]

上記の例は次のようになります。

Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]

値をコピーするのではなく、値を取る

通常、あなたが喜んでそうならselect、おそらくあなたは何かをコピーしています。値のみに関心がある場合、これは選択を回避するのに適したオプションです。

Range("B1:B6").Value = Range("A1:A6").Value


常にワークシートも参照するようにしてください

これはおそらく最も一般的な間違いです 。範囲をコピーするときはいつでも、ワークシートが参照されないことがあります。そのため、VBAは間違ったシートをActiveWorksheetと見なします。

'This will work only if the 2. Worksheet is selected!
Public Sub TestMe()
    Dim rng As Range
    Set rng = Worksheets(2).Range(Cells(1, 1), Cells(2, 2)).Copy
End Sub

'This works always!
Public Sub TestMe2()
    Dim rng As Range
    With Worksheets(2)
        .Range(.Cells(1, 1), .Cells(2, 2)).Copy
    End With
End Sub

私は実際に使うことはできません.Selectか、.Activate何のために?

  • 使用.Activateを正当化できる良い例であり.Select、視覚的な理由で特定のワークシートが選択されていることを確認したい場合です。たとえば、Excelは常に、ファイルが閉じられたときのActiveSheetに関係なく、最初に選択されたカバーワークシートで開きます。

したがって、以下のコードのようなものは絶対に問題ありません:

Private Sub Workbook_Open()
    Worksheets("Cover").Activate
End Sub

Worksheets.Activateの代わりにApplication.Gotoを使用できます。ややリスクが低い。
Geoff Griswald

1
返信が遅くなりました.Select- 必要に応じたすばらしい予想外の例と私の回避 策- すべてのシートに同じ情報を書き込む方法 -@Vityata :)
TM

1
@TMは-確かにそれは興味深い一例であり、おそらく100枚の+ワークシートのためのいくつかのミリ秒を節約する、しかし、私はどこかでそれを見た場合、私はおそらく、それを阻止するだろう。とにかく、そこにあるセレクションは明示的には書かれていませんが、の結果です.FillAcrossSheets。したがって、これはその中間(少なくともVBAタクソノミーについての私の考えでは)
Vityata

17

常にワークブック、ワークシート、セル/範囲を明記してください。

例えば:

Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)

エンドユーザーは常にボタンをクリックするだけなので、フォーカスがワークブックから外れるとすぐに、コードで作業したいと思うと、完全に問題が発生します。

また、ワークブックのインデックスを使用しないでください。

Workbooks(1).Worksheets("fred").cells(1,1)

ユーザーがコードを実行したときに、他にどのブックが開かれるかはわかりません。


7
ワークシートの名前も変わる可能性があります。代わりにコードネームを使用してください。
リックはモニカを

確かに、ワークシート名は変わる可能性があります。しかし、コードを過度に複雑にしてそれを軽減しようとすることには同意しません。ユーザーがシートの名前を変更し、マクロが機能しなくなった場合、それはユーザーにあります。私は通常、ワークシート名が同じになると思います。特に重要なマクロについては、マクロ本体を起動する前に、フライト前のチェックを少し実行します。これは、見つかると予想されるすべてのシートが実際にそこにあることを確認するだけです。
Geoff Griswald

10

これらのメソッドはかなり非難されているので、砂に線を引くために@Vityataと@Jeepedを先導します。

なぜ呼び出さない.Activate.SelectSelectionActiveSomethingメソッド/プロパティ

基本的に、それらは主にアプリケーションUIを介してユーザー入力を処理するために呼び出されるためです。これらは、ユーザーがUIを介してオブジェクトを処理するときに呼び出されるメソッドであるため、マクロレコーダーによって記録されたものであり、そのため、ほとんどの状況でそれらを呼び出すのは脆弱であるか、冗長です。Selection直後にアクションを実行するようにオブジェクト。

ただし、この定義は、それらが要求される状況を解決します。

ときに呼び出す.Activate.Select.Selection.ActiveSomethingメソッド/プロパティ

基本的に、最終ユーザーが実行で役割を果たすことを期待する場合。

開発していて、ユーザーがコードで処理するオブジェクトインスタンスを選択することを期待している場合は、.Selectionまたは.ActiveObjectが適切です。

一方、.Selectそして.Activateあなたは、ユーザーの次のアクションを推測することができますし、あなたのコードがユーザーをガイドしたい、おそらく彼にいくつかの時間とマウスクリックを保存する際に有用です。たとえば、コードでグラフの新しいインスタンスを作成したり、インスタンスを更新したりした場合、ユーザーはそれをチェックアウトする必要があり、ユーザーはそのコード.Activateまたはそのシートを呼び出して、ユーザーが検索する時間を節約できます。または、ユーザーが一部の範囲値を更新する必要があることがわかっている場合は、プログラムでその範囲を選択できます。


6

私見の使用は.select、私と同じようにマクロを記録し.select、それに気づかずにコードを変更することで必要に応じてVBAを学び始めた人々から来ていますselection

.select 既に投稿されているように、既存のオブジェクトを直接操作することで回避できます。これにより、複雑な方法でiとjを計算してからcell(i、j)を編集するなど、さまざまな間接参照が可能になります。

それ以外の場合は、.selectそれ自体に暗黙的な問題はなく、簡単に使用できます。たとえば、日付を入力したスプレッドシートを用意し、それを使用して何らかの魔法をかけ、別のシートに適切な形式でエクスポートするマクロをアクティブにします。ただし、隣接セルへの最終的な手動(予測不能)入力が必要です。そのため.select、追加のマウスの動きとクリックを省く瞬間がここにあります。


2
あなたの言う通りですが、selectには暗黙のうちに少なくとも1つの問題があります。それは遅いことです。マクロで発生する他のすべてと比較して、実際には非常に遅い。
16年

4

素早い回答:

.Selectメソッドの使用を回避するために、必要なプロパティに等しい変数を設定できます。

►たとえば、値を取得したい場合Cell A1は、そのセルのvalueプロパティに等しい変数を設定できます。

  • valOne = Range("A1").Value

►たとえば、「Sheet3」のコードネームが必要な場合は、そのワークシートのcodenameプロパティに等しい変数を設定できます。

  • valTwo = Sheets("Sheet3").Codename

お役に立てば幸いです。ご不明な点がありましたらお知らせください。


3

これらの回答のどれも.Offsetプロパティについて言及していないことに気づきました。これはSelect、特定のセルを操作するときのアクションの使用を回避するためにも使用できます(特にOPがで言及しているようにActiveCell)。

ここにいくつかの例があります。

また、「ActiveCell」はJ4であると想定します。

ActiveCell.Offset(2, 0).Value = 12

  • これにより、セルJ6が値12に変更されます
  • マイナス-2はJ2を参照します

ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)

  • これにより、セルがにコピーさk4L4ます。
  • 必要がない場合、オフセットパラメータに「0」は必要ないことに注意してください(、2)
  • 前の例と同様に、マイナス1は i4

ActiveCell.Offset(, -1).EntireColumn.ClearContents

  • これにより、列kのすべてのセルの値がクリアされます。

これらは、上記のオプションよりも「優れている」と言っているのではなく、代替案をリストしているだけです。


0

.Parent機能の使用。この例では、myRng参照を1つだけ設定すると、.Select、.Activate、.Activecell、.ActiveWorkbook、.ActiveSheetなどを使用せずに、環境全体に動的にアクセスできるようになります。(一般的な.Child機能はありません)

Sub ShowParents()
    Dim myRng As Range
    Set myRng = ActiveCell
    Debug.Print myRng.Address                    ' an address of the selected cell
    Debug.Print myRng.Parent.name                ' the name of sheet, where MyRng is in
    Debug.Print myRng.Parent.Parent.name         ' the name of workbook, where MyRng is in
    Debug.Print myRng.Parent.Parent.Parent.name  ' the name of application, where MyRng is in

    ' You may use this feature to set reference to these objects
    Dim mySh    As Worksheet
    Dim myWbk   As Workbook
    Dim myApp   As Application

    Set mySh = myRng.Parent
    Set myWbk = myRng.Parent.Parent
    Set myApp = myRng.Parent.Parent.Parent
    Debug.Print mySh.name, mySh.Cells(10, 1).Value
    Debug.Print myWbk.name, myWbk.Sheets.Count
    Debug.Print myApp.name, myApp.Workbooks.Count

    ' You may use dynamically addressing
    With myRng
        .Copy

       ' pastes in D1 on sheet 2 in the same workbook, where copied cell is
        .Parent.Parent.Sheets(2).Range("D1").PasteSpecial xlValues
    ' or myWbk.Sheets(2).Range("D1").PasteSpecial xlValues

       ' we may dynamically call active application too
        .Parent.Parent.Parent.CutCopyMode = False
    ' or myApp.CutCopyMode = False
    End With
End Sub

とてもいいですが、これがOPの質問とどう関係しているのかはわかりません。あなたは、選択またはActiveSheet使用せずに、VBAでの仕事にまったく「親」を必要としない
ジェフGriswald

0

SelectまたはActivesheetを使用しない主な理由は、ほとんどの人がマクロを実行するとき、およびマクロの実行中にシートから他の場所をクリックして別の場所をクリックすると、少なくとも別の2〜3のブックが開かれるためです。それらが開いている本、次に「アクティブシート」が変更され、修飾されていない「選択」コマンドのターゲットワークブックも変更されます。

せいぜい、マクロはクラッシュしますが、最悪の場合、誤ったブックの値を書き込んだり、セルを変更したりして、それらを「元に戻す」方法がありません。

私が従う単純なゴールデンルールがあります。WorkbookオブジェクトとWorksheetオブジェクトに「wb」と「ws」という名前の変数を追加し、常にそれらを使用してマクロブックを参照します。複数の本または複数のシートを参照する必要がある場合は、さらに変数を追加します。

例えば

Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")

「Set wb = ThisWorkbook」コマンドは絶対に重要です。「ThisWorkbook」はExcelの特別な値であり、VBAコードが現在実行されているワークブックを意味します。Workbook変数を設定するための非常に便利なショートカット。

Subの上部でそれを行った後、それらを使用するのは簡単ではありません。「選択」を使用する場所ならどこでも使用してください。

したがって、「出力」のセル「A1」の値を「Hello」に変更するには、次の代わりに:

Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"

これを行うことができます:

ws.Range("A1").Value = "Hello"

これは、ユーザーが複数のスプレッドシートで作業している場合に、信頼性が大幅に向上し、クラッシュする可能性が低くなるだけでなく、記述がはるかに短く、速く、簡単になります。

追加のボーナスとして、変数に常に「wb」と「ws」という名前を付けると、コードを1つの本から別の本にコピーして貼り付けることができます。


1
私の反対票ではありませんが、これが既存の回答ですでに提案されているものに新しい何かを追加するとは思いません。
BigBen

ええ、私の答えは少し冗長ですが、他の答えは長すぎ、余計なものが含まれており、ThisWorkbookを使用してワークシート変数を事前に設定することについて誰も言及していません。これは、初めてVBAにつま先をつけたときに誰かが私に見せてくれたとしたら、信じられないほど役に立ちました。他の人はワークシート変数の使用に言及しましたが、その理由を実際に説明せず、ワークシートおよびワークブック変数を使用する場合と使用しない場合のコードの例を提供しません。
ジェフグリスワルド

しかし、受け入れられた答えは間違いなく議論していThisWorkbookます...あなたのコメントが正確であるかどうかはわかりません。
BigBen

それはそうです、あなたは間違っていません。しかし、それを使用してワークブック変数を設定し、そのワークブック変数を今後使用する、またはそのワークブック変数を使用してワークシート変数を設定するというコンテキストでは、私が示唆しているようにではありません。私の答えは、受け入れられた答えよりも短く、シンプルで、初心者にとってアクセスしやすいものです。
Geoff Griswald

-3

これは、セル「A1」のコンテンツをクリアする例です(選択タイプがxllastcellなどの場合はさらに多く)。セルを選択せず​​にすべて完了。

Application.GoTo Reference:=Workbook(WorkbookName).Worksheets(WorksheetName).Range("A1")
Range(Selection,selection(selectiontype)).clearcontents 

これが誰かの役に立つことを願っています。


1
いいえ、ごめんなさい。それはあなたがそこでやったことでは全くありません。実際に行ったことは、 "Application.GoTo"コマンドを使用してセル "A1"を選択することです。これは、実際に "Select"を使用してから、選択内容にclearcontentsを使用することと同じです。セルを選択せず​​にそれを行う方法は、Workbook(WorkbookName).Worksheets(WorksheetName).Range("A1").ClearContents2行ではなく1行で、実際にはセルを選択せず​​に機能します。
Geoff Griswald
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.