.Select
Excel VBAを使用することの理解できる嫌悪感についてはよく耳にしますが、それを使用しないようにする方法がわかりません。関数の代わりに変数を使用できれば、コードの再利用性が向上することがわかりましたSelect
。ただし、 をActiveCell
使用しない場合の参照方法 ( など) がわかりませんSelect
。
範囲に関するこの記事と、 select を使用しない利点に関するこの例を見つけましたが、 how については何も見つかりません。
.Select
Excel VBAを使用することの理解できる嫌悪感についてはよく耳にしますが、それを使用しないようにする方法がわかりません。関数の代わりに変数を使用できれば、コードの再利用性が向上することがわかりましたSelect
。ただし、 をActiveCell
使用しない場合の参照方法 ( など) がわかりませんSelect
。
範囲に関するこの記事と、 select を使用しない利点に関するこの例を見つけましたが、 how については何も見つかりません。
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することをお勧めします。
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
orのみを使用する場合を除いて、変数もThisWorkbook
Dimすることをお勧めします。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
範囲を範囲変数としてSub
sとsに渡します。Function
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
これは、可能なことのための小さなテイスターです。
.Select
、.Activate
、Selection
、Activecell
、などActivesheet
をActiveworkbook
避けるべき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
それは良い答えですが、このトピックで見逃しているのは、Activate が実際に必要な場合です。誰もが悪いと言っていますが、それを使用することが理にかなっているケースについては誰も説明していません。
使用を避けられない状況.Activate/.Select
。(見つけ次第、リンクを追加します)
.Activate
Text To Columns
.Formula = .Formula
.Select
「... そして、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
ください。ワークシートのプロパティとして、他にも多くの目的があります。.Select
ActiveCell
(はい、この質問が に関するものであることは知っていますが、そう.Select
ではありませんSelection
が、初心者の VBA コーダーが推測する可能性のある誤解を取り除きたいと思いました。)
以下では、選択アプローチ(OPが避けたいアプローチ)と範囲アプローチを比較していることに注意してください(これが質問への答えです)。したがって、最初の 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
Select
andを回避Activate
することで、VBA 開発者としての能力を少し高めることができます。一般に、Select
とActivate
はマクロの記録時に使用されるため、Parent
ワークシートまたは範囲は常にアクティブなものと見なされます。
Select
これは、Activate
次の場合に回避する方法です。
From (マクロレコーダーで生成されたコード):
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
何かをコピーしている可能性が高いでしょう。値のみに関心がある場合は、select を避けるのに適したオプションです。
Range("B1:B6").Value = Range("A1:A6").Value
これはおそらくvbaで最も一般的な間違いです。範囲をコピーするたびに、ワークシートが参照されないことがあるため、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
、視覚的な理由で特定のワークシートが選択されていることを確認したい場合です。たとえば、ファイルが閉じられたときにどれが ActiveSheet であったかに関係なく、Excel は常に最初に選択された表紙のワークシートで開きます。したがって、以下のコードのようなものはまったく問題ありません。
Private Sub Workbook_Open()
Worksheets("Cover").Activate
End Sub
もう 1 つの良い例は、この例で説明したように、すべてのシートを 1 つの PDF ファイルにエクスポートする必要がある場合です。
コマンドがActiveWindow.ZoomやActiveWindow.FreezePanesActiveWindow
などでのみ機能する場合
ワークブック、ワークシート、およびセル/範囲を常に記述します。
例えば:
Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)
エンド ユーザーは常にボタンをクリックするだけなので、フォーカスがワークブックの外に移動するとすぐに、コードが操作したいものになり、事態は完全に悪化します。
ワークブックのインデックスは使用しないでください。
Workbooks(1).Worksheets("fred").cells(1,1)
ユーザーがコードを実行したときに、他のどのブックが開かれるかわかりません。
これらの方法はかなり汚名を着せられているため、一線を画すために Vityataと Jeeped を使用します。
.Activate
、、、メソッド/プロパティ.Select
を呼び出すSelection
ActiveSomething
基本的に、それらは主にアプリケーション UI を介してユーザー入力を処理するために呼び出されるためです。これらは、ユーザーが UI を介してオブジェクトを処理するときに呼び出されるメソッドであるため、マクロ レコーダーによって記録されます。そのため、ほとんどの状況で呼び出しが脆弱または冗長になります。Selection
直後にアクションを実行するためのオブジェクト。
ただし、この定義は、それらが求められる状況を解決します。
.Activate
、、、メソッド/プロパティ.Select
をいつ呼び出す.Selection
か.ActiveSomething
基本的に、最終ユーザーが実行で役割を果たすと予想される場合。
開発中で、ユーザーがコードで処理するオブジェクト インスタンスを選択することを期待している場合は、.Selection
適切.ActiveObject
です。
一方、.Select
and.Activate
は、ユーザーの次のアクションを推測でき、コードでユーザーをガイドして、ユーザーの時間とマウス クリックを節約したい場合に役立ちます。たとえば、コードがチャートの新しいインスタンスまたは更新されたチャートのインスタンスを作成したばかりの場合、ユーザーはそれをチェックアウトしたいと思うかもしれません。.Activate
その場合、それまたはそのシートを呼び出して、ユーザーが検索する時間を節約できます。または、ユーザーが一部の範囲値を更新する必要があることがわかっている場合は、プログラムでその範囲を選択できます。
私見の使用は、私のように、必要に応じてマクロを記録し、それ.select
を認識せずにコードを変更することで VBA を学習し始めた人々から来ています。.select
selection
.select
すでに投稿されている多くのように、既存のオブジェクトを直接操作することで回避できます。これにより、複雑な方法で i と j を計算してから cell(i,j) を編集するなど、さまざまな間接参照が可能になります。
それ以外の場合は、.select
それ自体に暗黙のうちに問題はなく、これの用途を簡単に見つけることができます。たとえば、日付を入力したスプレッドシートがあり、それを使って魔法を行うマクロをアクティブにし、別のシートに許容可能な形式でエクスポートします。ただし、隣接するセルへの最終的な手動 (予測不可能な) 入力が必要です。そのため.select
、マウスの移動とクリックを追加する必要がなくなりました。
メソッドの使用を避けるため.Select
に、必要なプロパティに等しい変数を設定できます。
► たとえば、値がCell A1
必要な場合は、そのセルの値プロパティに等しい変数を設定できます。
valOne = Range("A1").Value
► たとえば、you could set a variable equal to the
そのワークシートの 'Sheet3 Codename` プロパティのコードネームが必要な場合。
valTwo = Sheets("Sheet3").Codename
これらの回答のどれも.Offset Propertyについて言及していないことに気付きました。Select
これは、特定のセルを操作するときに、特に選択したセルを参照してアクションを使用しないようにするためにも使用できます(OP で言及されているようにActiveCell
)。
ここにいくつかの例があります。
また、「ActiveCell」がJ4であると仮定します。
ActiveCell.Offset(2, 0).Value = 12
J6
の値が 12 に変更されますActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)
k4
れL4
ます。i4
ActiveCell.Offset(, -1).EntireColumn.ClearContents
これらは、上記のオプションよりも「優れている」と言っているのではなく、代替案をリストしているだけです.