640 Stimmen

Wie man die Verwendung von Select in Excel VBA vermeidet

Ich habe viel über die verständliche Abneigung gegen die Verwendung von .Select in Excel VBA, aber ich bin mir nicht sicher, wie ich das vermeiden kann. Ich bin der Meinung, dass mein Code besser wiederverwendbar wäre, wenn ich Variablen anstelle von Select Funktionen. Ich bin mir jedoch nicht sicher, wie ich auf Dinge verweisen soll (wie die ActiveCell usw.), wenn nicht mit Select .

Ich habe gefunden dieser Artikel über Reichweiten y dieses Beispiel über die Vorteile der Nichtverwendung von select aber ich kann nichts finden über wie .

671voto

chris neilsen Punkte 50473

Einige Beispiele für die Vermeidung der Auswahl

Utilice Dim Variablen

Dim rng as Range

Set die Variable auf den gewünschten Bereich. Es gibt viele Möglichkeiten, sich auf einen Bereich für eine einzelne Zelle zu beziehen:

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

Oder ein mehrzelliges Angebot:

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)

Usted puede verwenden Sie die Abkürzung zum Evaluate Methode, aber dies ist weniger effizient und sollte im Allgemeinen in Produktionscode vermieden werden.

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

Alle oben genannten Beispiele beziehen sich auf Zellen auf der Seite aktives Blatt . Wenn Sie nicht ausdrücklich nur mit dem aktiven Blatt arbeiten wollen, ist es besser, ein Dim Worksheet auch variabel:

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

Wenn Sie 為さる wollen mit dem ActiveSheet Um Klarheit zu schaffen, ist es am besten, sich klar auszudrücken. Aber Vorsicht, denn einige Worksheet Methoden ändern das aktive Blatt.

Set rng = ActiveSheet.Range("A1")

Dies bezieht sich wiederum auf die aktive Arbeitsmappe . Wenn Sie nicht ausdrücklich nur mit dem ActiveWorkbook o ThisWorkbook ist es besser, ein Dim Workbook auch variabel.

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

Wenn Sie 為さる wollen mit dem ActiveWorkbook Um Klarheit zu schaffen, ist es am besten, sich klar auszudrücken. Aber Vorsicht, da viele WorkBook Methoden ändern das aktive Buch.

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

Sie können auch die ThisWorkbook Objekt, um auf das Buch zu verweisen, das den laufenden Code enthält.

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

Ein gängiges (schlechtes) Codestück ist das Öffnen eines Buches, das Abrufen von Daten und das erneute Schließen

Das ist schlecht:

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

Und es wäre besser so:

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

Übergeben Sie Bereiche an Ihre Sub s und Function s als Bereichsvariablen:

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

Sie sollten auch Methoden anwenden (wie Find y Copy ) zu Variablen:

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

Wenn Sie eine Schleife über einen Bereich von Zellen ziehen, ist es oft besser (schneller), die Werte des Bereichs zuerst in ein Varianten-Array zu kopieren und eine Schleife darüber zu ziehen:

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

Dies ist ein kleiner Vorgeschmack auf das, was möglich ist.

254voto

Siddharth Rout Punkte 143513

Dafür gibt es zwei Hauptgründe .Select , .Activate , Selection , Activecell , Activesheet , Activeworkbook usw. sollten vermieden werden.

  1. Es verlangsamt Ihren Code.
  2. Sie ist in der Regel die Hauptursache für Laufzeitfehler.

Wie können wir sie vermeiden?

1) Direktes Arbeiten mit den entsprechenden Objekten

Betrachten Sie diesen Code

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

Dieser Code kann auch wie folgt geschrieben werden

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

2) Deklarieren Sie bei Bedarf Ihre Variablen. Derselbe Code wie oben kann wie folgt geschrieben werden

Dim ws as worksheet

Set ws = Sheets("Sheet1")

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

Das ist eine gute Antwort, aber was mir bei diesem Thema fehlt, ist die Frage, wann wir Activate tatsächlich brauchen. Alle sagen, dass es schlecht ist, aber niemand erklärt, in welchen Fällen es sinnvoll ist, es zu verwenden.

Situation, wenn Sie kann nicht vermeiden mit .Activate/.Select . (Ich werde weitere Links hinzufügen, sobald ich sie gefunden habe)

  1. Wenn Sie einem Benutzer ein Arbeitsblatt so präsentieren möchten, dass er es sehen kann.
  2. Szenarien wie Arbeitsmakro gibt Fehler zurück, wenn es vom Formularsteuerelement aus ausgeführt wird wo Sie gezwungen sind, die .Activate
  3. Wenn übliche Methoden de Text To Columns / .Formula = .Formula nicht funktioniert, müssen Sie möglicherweise auf .Select

110voto

Rick supports Monica Punkte 38114

Zu all den hervorragenden Antworten, die bereits gegeben wurden, möchte ich noch einen kleinen Punkt hinzufügen:

Das Wichtigste, was Sie tun können, um die Verwendung von Select zu vermeiden, ist wahrscheinlich, dass Sie Verwenden Sie so oft wie möglich benannte Bereiche (kombiniert mit aussagekräftigen Variablennamen) in Ihrem VBA-Code. . Dieser Punkt wurde bereits erwähnt, aber ein wenig beschönigt; er verdient jedoch besondere Aufmerksamkeit.

Hier einige weitere Gründe für die großzügige Verwendung von benannten Bereichen, wobei mir sicher noch mehr einfallen würden.

Benannte Bereiche machen Ihren Code einfacher zu lesen und zu verstehen.

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

Es ist ziemlich offensichtlich, was die genannten Bereiche Months y MonthlySales enthalten, und was das Verfahren bewirkt.

Warum ist das wichtig? Zum Teil, weil es für andere Leute einfacher ist, ihn zu verstehen. Aber selbst wenn Sie die einzige Person sind, die Ihren Code jemals sehen oder verwenden wird, sollten Sie dennoch benannte Bereiche und gute Variablennamen verwenden, weil werden Sie vergessen was Sie ein Jahr später damit machen wollten, und du wirst verschwenden 30 Minuten, um herauszufinden, was Ihr Code macht.

Benannte Bereiche sorgen dafür, dass Ihre Makros weit weniger wahrscheinlich kaputt gehen, wenn sich die Konfiguration des Arbeitsblatts ändert (nicht wenn!).

Stellen Sie sich vor, das obige Beispiel wäre so geschrieben worden:

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

Dieser Code wird anfangs gut funktionieren - bis Sie oder ein zukünftiger Benutzer beschließt: "Mensch, ich glaube, ich werde eine neue Spalte mit dem Jahr in Spalte A !", oder fügen Sie eine Ausgabenspalte zwischen den Monats- und Umsatzspalten ein, oder fügen Sie jeder Spalte eine Überschrift hinzu. Jetzt ist Ihr Code kaputt. Und weil Sie schreckliche Variablennamen verwendet haben, werden Sie viel mehr Zeit brauchen, um herauszufinden, wie Sie das Problem beheben können, als es eigentlich sein sollte.

Wenn Sie anfangs benannte Bereiche verwendet haben, wird die Months y Sales Die Spalten können beliebig verschoben werden, und Ihr Code würde weiterhin problemlos funktionieren.

55voto

MattB Punkte 2103

Ich werde die kurze Antwort geben, da alle anderen die lange Antwort gegeben haben.

Sie erhalten .select und .activate, wenn Sie Makros aufzeichnen und wiederverwenden. Wenn Sie eine Zelle oder ein Blatt mit .select auswählen, wird diese(s) einfach aktiviert. Von diesem Zeitpunkt an können Sie bei der Verwendung von unqualifizierten Verweisen wie Range.Value sie verwenden nur die aktive Zelle und das Blatt. Dies kann auch problematisch sein, wenn Sie nicht darauf achten, wo Ihr Code platziert wird oder ein Benutzer auf die Arbeitsmappe klickt.

Sie können diese Probleme also vermeiden, indem Sie direkt auf Ihre Zellen verweisen. Das geht:

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

Oder Sie könnten

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

Es gibt verschiedene Kombinationen dieser Methoden, aber das wäre die allgemeine Idee, die für ungeduldige Menschen wie mich so kurz wie möglich ausgedrückt werden sollte.

40voto

"... und stelle fest, dass mein Code besser wiederverwendbar wäre, wenn ich Variablen anstelle von Select-Funktionen verwenden könnte."

Ich kann mir zwar nur eine Handvoll von Situationen vorstellen, in denen .Select eine bessere Wahl als eine direkte Zellreferenzierung wäre, würde ich mich für die Verteidigung der Selection und weisen darauf hin, dass sie nicht aus denselben Gründen verworfen werden sollte, die .Select sollten vermieden werden.

Kurze, zeitsparende Makrounterprogramme, die Tastenkombinationen zugewiesen sind, die mit ein paar Tastendrücken abgerufen werden können, sparen eine Menge Zeit. Die Möglichkeit, eine Gruppe von Zellen auszuwählen, auf die der operative Code angewendet werden soll, wirkt Wunder, wenn Sie mit Daten arbeiten, die nicht einem arbeitsblattweiten Datenformat entsprechen. Ähnlich wie Sie eine Gruppe von Zellen auswählen und eine Formatänderung vornehmen können, kann die Auswahl einer Gruppe von Zellen, auf die ein spezieller Makrocode angewendet werden soll, eine große Zeitersparnis bedeuten.

Beispiele für einen selektionsbasierten Teilrahmen:

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

Der zu verarbeitende Code kann von einer einzelnen Zeile bis zu mehreren Modulen alles sein. Ich habe diese Methode verwendet, um lang laufende Routinen für eine unregelmäßige Auswahl von Zellen zu starten, die die Dateinamen externer Arbeitsmappen enthalten.

Kurz gesagt, werfen Sie nicht weg Selection aufgrund seiner engen Verbindung mit .Select y ActiveCell . Als Arbeitsblatteigenschaft hat sie viele andere Zwecke.

(Ja, ich weiß, die Frage bezog sich auf <code>.Select</code> ではなく <code>Selection</code> aber ich wollte alle Missverständnisse ausräumen, die von VBA-Anfängern geäußert werden könnten).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X