Come evitare di utilizzare Seleziona in Excel VBA
Ho sentito molto parlare della comprensibile ripugnanza dell'utilizzo .Select
in Excel VBA, ma non sono sicuro di come evitare di usarlo. Sto scoprendo che il mio codice sarebbe più riutilizzabile se fossi in grado di utilizzare variabili invece di Select
funzioni. Tuttavia, non sono sicuro di come fare riferimento a cose (come ActiveCell
, ecc.) Se non lo uso Select
.
Ho trovato questo articolo sugli intervalli e questo esempio sui vantaggi di non utilizzare select , ma non riesco a trovare nulla su come .
Risposte
Alcuni esempi di come evitare select
Usa Dim
le variabili 'd
Dim rng as Range
Set
la variabile all'intervallo richiesto. Esistono molti modi per fare riferimento a un intervallo di celle singole:
Set rng = Range("A1")
Set rng = Cells(1, 1)
Set rng = Range("NamedRange")
O un intervallo multicella:
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)
È possibile utilizzare il collegamento al Evaluate
metodo, ma questo è meno efficiente e dovrebbe essere generalmente evitato nel codice di produzione.
Set rng = [A1]
Set rng = [A1:B10]
Tutti gli esempi precedenti si riferiscono alle celle del foglio attivo . A meno che tu non voglia specificamente lavorare solo con il foglio attivo, è meglio anche Dim una Worksheet
variabile:
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
Se non vogliono lavorare con il ActiveSheet
, per chiarezza è meglio essere espliciti. Ma attenzione, poiché alcuni Worksheet
metodi cambiano il foglio attivo.
Set rng = ActiveSheet.Range("A1")
Ancora una volta, questo si riferisce alla cartella di lavoro attiva . A meno che tu non voglia specificamente lavorare solo con ActiveWorkbook
o ThisWorkbook
, è meglio anche Dim una Workbook
variabile.
Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")
Se non vogliono lavorare con il ActiveWorkbook
, per chiarezza è meglio essere espliciti. Ma attenzione, poiché molti WorkBook
metodi cambiano il libro attivo.
Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")
È inoltre possibile utilizzare l' ThisWorkbook
oggetto per fare riferimento al libro contenente il codice in esecuzione.
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")
Un pezzo di codice comune (cattivo) è aprire un libro, ottenere alcuni dati e poi chiuderlo di nuovo
Questo non va bene:
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
E sarebbe meglio come:
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
Passo va ai vostri Sub
s ed Function
s come variabili Gamma:
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
Dovresti anche applicare metodi (come Find
e Copy
) alle variabili:
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
Se esegui il ciclo su un intervallo di celle, spesso è meglio (più veloce) copiare prima i valori dell'intervallo su un array variante e ripetere il ciclo su quello:
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
Questo è un piccolo assaggio di ciò che è possibile.
Due motivi principali per cui .Select
, .Activate
, Selection
, Activecell
, Activesheet
, Activeworkbook
, ecc dovrebbe essere evitato
- Rallenta il tuo codice.
- Di solito è la causa principale degli errori di runtime.
Come lo evitiamo?
1) Lavora direttamente con gli oggetti rilevanti
Considera questo codice
Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"
Questo codice può anche essere scritto come
With Sheets("Sheet1").Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
2) Se necessario, dichiara le tue variabili. Lo stesso codice sopra può essere scritto come
Dim ws as worksheet
Set ws = Sheets("Sheet1")
With ws.Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
Aggiungerò un piccolo punto di enfasi a tutte le eccellenti risposte fornite in precedenza:
Probabilmente la cosa più importante che puoi fare per evitare di utilizzare Seleziona è, per quanto possibile, utilizzare intervalli denominati (combinati con nomi di variabili significativi) nel codice VBA . Questo punto è stato menzionato sopra, ma è stato un po 'sorvolato; tuttavia, merita un'attenzione speciale.
Ecco un paio di motivi aggiuntivi per fare un uso liberale di intervalli denominati, anche se sono sicuro che potrei pensare a qualcosa di più.
Gli intervalli denominati semplificano la lettura e la comprensione del codice.
Esempio:
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
È abbastanza ovvio cosa contengono Months
e gli intervalli denominati MonthlySales
e cosa sta facendo la procedura.
Perché questo è importante? In parte perché è più facile per altre persone capirlo, ma anche se sei l'unica persona che vedrà o utilizzerà il tuo codice, dovresti comunque usare intervalli denominati e buoni nomi di variabili perché dimenticherai cosa intendevi farne un anno dopo, e sprecherai 30 minuti solo per capire cosa sta facendo il tuo codice.
Gli intervalli denominati assicurano che le macro non si interrompano quando (non se!) La configurazione del foglio di calcolo cambia.
Considera, se l'esempio precedente fosse stato scritto in questo modo:
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
All'inizio questo codice funzionerà perfettamente, ovvero fino a quando tu o un futuro utente non deciderete "gee wiz, penso che aggiungerò una nuova colonna con l'anno nella colonna A
!", O inserirete una colonna delle spese tra i mesi e colonne delle vendite o aggiungi un'intestazione a ciascuna colonna. Ora, il tuo codice è rotto. E poiché hai usato nomi di variabili terribili, ti ci vorrà molto più tempo per capire come risolverlo di quanto dovrebbe.
Se avessi usato intervalli denominati per cominciare, le colonne Months
e Sales
potrebbero essere spostate come preferisci e il tuo codice continuerebbe a funzionare perfettamente.
Darò la risposta breve poiché tutti gli altri hanno dato quella lunga.
Otterrai .select e .activate ogni volta che registri macro e le riutilizzi. Quando selezioni una cella o un foglio, questo lo rende attivo. Da quel momento in poi ogni volta che usi riferimenti non qualificati come Range.Value
se usassero semplicemente la cella e il foglio attivi. Questo può anche essere problematico se non guardi dove è posizionato il tuo codice o un utente fa clic sulla cartella di lavoro.
Quindi, puoi eliminare questi problemi facendo riferimento direttamente alle tue celle. Che va:
'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)
Oppure potresti
'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"
Ci sono varie combinazioni di questi metodi, ma questa sarebbe l'idea generale espressa il più presto possibile per le persone impazienti come me.
"... e sto scoprendo che il mio codice sarebbe più riutilizzabile se fossi in grado di utilizzare le variabili invece delle funzioni di selezione."
Sebbene non riesca a pensare a nient'altro che a una manciata isolata di situazioni in cui .Select
sarebbe una scelta migliore rispetto al riferimento diretto alle celle, mi solleverei in difesa Selection
e sottolineerei che non dovrebbe essere buttato fuori per le stesse ragioni che .Select
dovrebbero essere evitate.
Ci sono momenti in cui avere sottoprogrammi macro brevi e che fanno risparmiare tempo assegnate a combinazioni di tasti di scelta rapida disponibili con il semplice tocco di un paio di tasti fa risparmiare molto tempo. Essere in grado di selezionare un gruppo di celle per emanare il codice operativo funziona a meraviglia quando si tratta di dati intascati che non sono conformi a un formato di dati a livello di foglio di lavoro. Più o meno nello stesso modo in cui potresti selezionare un gruppo di celle e applicare un cambio di formato, selezionare un gruppo di celle su cui eseguire un codice macro speciale può essere un importante risparmio di tempo.
Esempi di sottostruttura basata sulla selezione:
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
Il codice effettivo da elaborare potrebbe essere qualsiasi cosa, da una singola riga a più moduli. Ho usato questo metodo per avviare routine di lunga durata su una selezione irregolare di celle contenenti i nomi dei file di cartelle di lavoro esterne.
In breve, non scartare a Selection
causa della sua stretta associazione con .Select
e ActiveCell
. Come proprietà del foglio di lavoro, ha molti altri scopi.
(Sì, so che questa domanda riguardava .Select
, no, Selection
ma volevo rimuovere qualsiasi idea sbagliata che i programmatori VBA inesperti potrebbero dedurre.)
Evitare Select
ed Activate
è la mossa che ti rende un po 'migliore sviluppatore VBA. In generale, Select
e Activate
vengono utilizzati quando viene registrata una macro, quindi il Parent
foglio di lavoro o l'intervallo è sempre considerato quello attivo.
Ecco come puoi evitare Select
e Activate
nei seguenti casi:
Aggiunta di un nuovo foglio di lavoro e copia di una cella su di esso:
Da (codice generato con registratore di macro):
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
Per:
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
Quando vuoi copiare l'intervallo tra i fogli di lavoro:
A partire dal:
Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste
Per:
Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")
Utilizzo di intervalli con nomi fantasiosi
Puoi accedervi con []
, che è davvero bello, rispetto all'altro modo. Controllati:
Dim Months As Range
Dim MonthlySales As Range
Set Months = Range("Months")
Set MonthlySales = Range("MonthlySales")
Set Months =[Months]
Set MonthlySales = [MonthlySales]
L'esempio dall'alto sarebbe simile a questo:
Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]
Non copiare valori, ma prenderli
Di solito, se lo desideri select
, molto probabilmente stai copiando qualcosa. Se sei interessato solo ai valori, questa è una buona opzione per evitare di selezionare:
Range("B1:B6").Value = Range("A1:A6").Value
Prova sempre a fare riferimento anche al foglio di lavoro
Questo è probabilmente l'errore più comune in vba . Ogni volta che si copiano intervalli, a volte non viene fatto riferimento al foglio di lavoro e quindi VBA considera il foglio sbagliato l'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
Non posso davvero mai usare .Select
o .Activate
per niente?
- Un buon esempio di quando potresti essere giustificato nell'usare
.Activate
ed.Select
è quando vuoi assicurarti che un foglio di lavoro specifico sia selezionato per motivi visivi. Ad esempio, il tuo Excel si aprirà sempre con il foglio di lavoro di copertina selezionato per primo, ignorando quale fosse l'ActiveSheet quando il file è stato chiuso.
Quindi, qualcosa come il codice seguente è assolutamente OK:
Private Sub Workbook_Open()
Worksheets("Cover").Activate
End Sub
Un altro buon esempio è quando è necessario esportare tutti i fogli in un file PDF, come menzionato in questo caso - Come evitare le istruzioni select / active in VBA in questo esempio?
Quando un comando funziona solo con
ActiveWindow
come ActiveWindow.Zoom o ActiveWindow.FreezePanes
Si noti che di seguito sto confrontando l'approccio Select (quello che l'OP vuole evitare), con l'approccio Range (e questa è la risposta alla domanda). Quindi non smettere di leggere quando vedi il primo Seleziona.
Dipende davvero da cosa stai cercando di fare. Ad ogni modo, un semplice esempio potrebbe essere utile. Supponiamo che tu voglia impostare il valore della cella attiva su "foo". Usando ActiveCell scriveresti qualcosa del genere:
Sub Macro1()
ActiveCell.Value = "foo"
End Sub
Se vuoi usarlo per una cella che non è quella attiva, ad esempio per "B2", devi prima selezionarlo, in questo modo:
Sub Macro2()
Range("B2").Select
Macro1
End Sub
Usando gli intervalli puoi scrivere una macro più generica che può essere utilizzata per impostare il valore di qualsiasi cella che desideri su quello che vuoi:
Sub SetValue(cellAddress As String, aVal As Variant)
Range(cellAddress).Value = aVal
End Sub
Quindi puoi riscrivere Macro2 come:
Sub Macro2()
SetCellValue "B2", "foo"
End Sub
E Macro1 come:
Sub Macro1()
SetValue ActiveCell.Address, "foo"
End Sub
Indicare sempre la cartella di lavoro, il foglio di lavoro e la cella / intervallo.
Per esempio:
Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)
Perché gli utenti finali faranno sempre clic sui pulsanti e non appena il focus si sposta dalla cartella di lavoro il codice vuole lavorare, allora le cose vanno completamente storte.
E non usare mai l'indice di una cartella di lavoro.
Workbooks(1).Worksheets("fred").cells(1,1)
Non sai quali altre cartelle di lavoro saranno aperte quando l'utente eseguirà il tuo codice.
Questi metodi sono piuttosto stigmatizzati, quindi prendere il comando di Vityata e Jeeped per il gusto di tracciare una linea nella sabbia:
Chiamata .Activate
, .Select
, Selection
, ActiveSomething
i metodi / proprietà
Fondamentalmente perché vengono chiamati principalmente per gestire l'input dell'utente tramite l'interfaccia utente dell'applicazione. Poiché sono i metodi chiamati quando l'utente gestisce gli oggetti tramite l'interfaccia utente, sono quelli registrati dal registratore di macro, ed è per questo che chiamarli è fragile o ridondante per la maggior parte delle situazioni: non è necessario selezionare un oggetto in modo da eseguire un'azione con Selection
subito dopo.
Tuttavia, questa definizione regola le situazioni in cui sono richiesti:
Quando chiamare .Activate
, .Select
, .Selection
, .ActiveSomething
i metodi / proprietà
Fondamentalmente quando ti aspetti che l' utente finale giochi un ruolo nell'esecuzione.
Se stai sviluppando e ti aspetti che l'utente scelga le istanze dell'oggetto che il tuo codice deve gestire, allora .Selection
o .ActiveObject
sei appropriato.
D'altra parte, .Select
e .Activate
sono utili quando puoi dedurre l'azione successiva dell'utente e vuoi che il tuo codice guidi l'utente, possibilmente risparmiandogli un po 'di tempo e clic del mouse. Ad esempio, se il tuo codice ha appena creato un'istanza nuova di zecca di un grafico o ne ha aggiornato uno, l'utente potrebbe volerlo controllare e potresti richiamarlo .Activate
o il suo foglio per risparmiare tempo all'utente che lo cerca; oppure, se sai che l'utente dovrà aggiornare alcuni valori dell'intervallo, puoi selezionare quell'intervallo a livello di codice.
L'utilizzo di IMHO .select
proviene da persone che come me hanno iniziato ad imparare VBA per necessità registrando macro e quindi modificando il codice senza rendersene conto .select
e il successivo selection
è solo un intermediario non necessario.
.select
può essere evitato, come molti già postati, lavorando direttamente con gli oggetti già esistenti, il che consente vari riferimenti indiretti come calcolare i e j in modo complesso e quindi modificare la cella (i, j), ecc.
Altrimenti, non c'è nulla di implicitamente sbagliato in .select
se stesso e puoi trovare facilmente degli usi per questo, ad esempio ho un foglio di calcolo che ho popolato con la data, attivo una macro che fa un po 'di magia con esso ed esporta in un formato accettabile su un foglio separato, che , tuttavia, richiede alcuni input manuali finali (imprevedibili) in una cella adiacente. Quindi ecco che arriva il momento per .select
questo mi fa risparmiare quel movimento e clic aggiuntivi del mouse.
Per evitare di utilizzare il .Select
metodo, puoi impostare una variabile uguale alla proprietà che desideri.
► Ad esempio, se si desidera inserire il valore, Cell A1
è possibile impostare una variabile uguale alla proprietà value di quella cella.
- Esempio
valOne = Range("A1").Value
► Ad esempio, se si desidera il nome in codice della you could set a variable equal to the
proprietà 'Sheet3 Codename` di quel foglio di lavoro.
- Esempio
valTwo = Sheets("Sheet3").Codename
Ho notato che nessuna di queste risposte menziona la proprietà .Offset . Questo può anche essere usato per evitare di usare l' Select
azione quando si manipolano determinate celle, in particolare in riferimento a una cella selezionata (come menzionato dall'OP ActiveCell
).
Ecco un paio di esempi.
Assumerò anche che "ActiveCell" sia J4 .
ActiveCell.Offset(2, 0).Value = 12
- Questo cambierà la cella
J6
con un valore di 12 - Un meno -2 avrebbe fatto riferimento a J2
ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)
- Questo copierà la cella in
k4
aL4
. - Nota che "0" non è necessario nel parametro offset se non è necessario (, 2)
- Simile all'esempio precedente sarebbe un meno 1
i4
ActiveCell.Offset(, -1).EntireColumn.ClearContents
- Ciò cancellerà i valori in tutte le celle nella colonna k.
Questi non vogliono dire che siano "migliori" delle opzioni di cui sopra, ma solo elencare le alternative.
Come evitare il copia-incolla?
Let's face it: this one appears a lot when recording macros:
Range("X1").Select
Selection.Copy
Range("Y9).Select
Selection.Paste
While the only thing the person wants is:
Range("Y9").Value = Range("X1").Value
Therefore, instead of using copy-paste in VBA macros, I'd advise the following simple approach:
Destination_Range.Value = Source_Range.Value
Working with the .Parent feature, this example shows how setting only one myRng reference enables dynamic access to the entire environment without any .Select, .Activate, .Activecell, .ActiveWorkbook, .ActiveSheet and so on. (There isn't any generic .Child feature.)
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 the 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
The main reason never to use Select or Activesheet is because most people will have at least another couple of workbooks open (sometimes dozens) when they run your macro, and if they click away from your sheet while your macro is running and click on some other book they have open, then the "Activesheet" changes, and the target workbook for an unqualified "Select" command changes as well.
At best, your macro will crash, at worst you might end up writing values or changing cells in the wrong workbook with no way to "Undo" them.
I have a simple golden rule that I follow: Add variables named "wb" and "ws" for a Workbook object and a Worksheet object and always use those to refer to my macro book. If I need to refer to more than one book, or more than one sheet, I add more variables.
For example,
Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")
The "Set wb = ThisWorkbook" command is absolutely key. "ThisWorkbook" is a special value in Excel, and it means the workbook that your VBA code is currently running from. A very helpful shortcut to set your Workbook variable with.
After you've done that at the top of your Sub, using them could not be simpler, just use them wherever you would use "Selection":
So to change the value of cell "A1" in "Output" to "Hello", instead of:
Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"
We can now do this:
ws.Range("A1").Value = "Hello"
Which is not only much more reliable and less likely to crash if the user is working with multiple spreadsheets; it's also much shorter, quicker and easier to write.
As an added bonus, if you always name your variables "wb" and "ws", you can copy and paste code from one book to another and it will usually work with minimal changes needed, if any.