592

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

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

4

16 に答える 16

618

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

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")

繰り返しますが、これはアクティブなワークブックを指します。特にActiveWorkbookorのみを使用する場合を除いて、変数もThisWorkbookDimすることをお勧めします。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と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

これは、可能なことのための小さなテイスターです。

于 2012-05-23T10:23:22.667 に答える
233

.Select.ActivateSelectionActivecell、などActivesheetActiveworkbook避けるべき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

それは良い答えですが、このトピックで見逃しているのは、Activate が実際に必要な場合です。誰もが悪いと言っていますが、それを使用することが理にかなっているケースについては誰も説明していません。

使用を避けられない状況.Activate/.Select。(見つけ次第、リンクを追加します)

  1. ユーザーがワークシートを表示できるように、ユーザーにワークシートを提示する場合。
  2. 使用を余儀なくされているフォームコントロールから実行すると、マクロがエラーを返すなどのシナリオ.Activate
  3. /の通常の方法が機能しない場合は、に頼る必要がある場合がありますText To Columns.Formula = .Formula.Select
于 2012-05-23T10:33:36.353 に答える
36

「... そして、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 コーダーが推測する可能性のある誤解を取り除きたいと思いました。)

于 2015-02-24T15:41:21.163 に答える
32

以下では、選択アプローチ(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
于 2012-05-23T06:11:28.830 に答える
32

Selectandを回避Activateすることで、VBA 開発者としての能力を少し高めることができます。一般に、SelectActivateはマクロの記録時に使用されるため、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 は間違ったシートを 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.ZoomActiveWindow.FreezePanesActiveWindowなどでのみ機能する場合

于 2016-03-08T10:04:12.147 に答える
18

ワークブック、ワークシート、およびセル/範囲を常に記述します。

例えば:

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

エンド ユーザーは常にボタンをクリックするだけなので、フォーカスがワークブックの外に移動するとすぐに、コードが操作したいものになり、事態は完全に悪化します。

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

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

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

于 2014-08-25T09:54:22.493 に答える
15

これらの方法はかなり汚名を着せられているため、一線を画すために Vityataと Jeeped を使用します。

.Activate、、、メソッド/プロパティ.Selectを呼び出すSelectionActiveSomething

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

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

.Activate、、、メソッド/プロパティ.Selectをいつ呼び出す.Selection.ActiveSomething

基本的に、最終ユーザーが実行で役割を果たすと予想される場合。

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

一方、.Selectand.Activateは、ユーザーの次のアクションを推測でき、コードでユーザーをガイドして、ユーザーの時間とマウス クリックを節約したい場合に役立ちます。たとえば、コードがチャートの新しいインスタンスまたは更新されたチャートのインスタンスを作成したばかりの場合、ユーザーはそれをチェックアウトしたいと思うかもしれません。.Activateその場合、それまたはそのシートを呼び出して、ユーザーが検索する時間を節約できます。または、ユーザーが一部の範囲値を更新する必要があることがわかっている場合は、プログラムでその範囲を選択できます。

于 2018-06-16T14:18:51.557 に答える
8

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

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

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

于 2016-11-20T15:02:00.710 に答える
7

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

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

  • valOne = Range("A1").Value

► たとえば、you could set a variable equal to theそのワークシートの 'Sheet3 Codename` プロパティのコードネームが必要な場合。

  • valTwo = Sheets("Sheet3").Codename
于 2016-09-08T06:36:33.133 に答える
5

これらの回答のどれも.Offset Propertyについて言及していないことに気付きました。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 のすべてのセルの値がクリアされます。

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

于 2018-08-16T20:07:44.717 に答える