Comment éviter d'utiliser Select dans Excel VBA
J'ai beaucoup entendu parler de l'horreur compréhensible de l'utilisation .Select
dans Excel VBA, mais je ne sais pas comment éviter de l'utiliser. Je trouve que mon code serait plus réutilisable si je pouvais utiliser des variables au lieu de Select
fonctions. Cependant, je ne sais pas comment faire référence à des choses (comme le ActiveCell
, etc.) si elles ne sont pas utilisées Select
.
J'ai trouvé cet article sur les gammes et cet exemple sur les avantages de ne pas utiliser select , mais je ne trouve rien sur comment .
Réponses
Quelques exemples pour éviter de sélectionner
Utiliser Dim
des variables 'd
Dim rng as Range
Set
la variable à la plage requise. Il existe de nombreuses façons de faire référence à une plage à une seule cellule:
Set rng = Range("A1")
Set rng = Cells(1, 1)
Set rng = Range("NamedRange")
Ou une gamme multi-cellules:
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)
Vous pouvez utiliser le raccourci vers la Evaluate
méthode, mais cela est moins efficace et doit généralement être évité dans le code de production.
Set rng = [A1]
Set rng = [A1:B10]
Tous les exemples ci-dessus font référence à des cellules de la feuille active . À moins que vous ne souhaitiez spécifiquement travailler uniquement avec la feuille active, il est également préférable d'atténuer une Worksheet
variable:
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
Si vous ne voulez travailler avec la ActiveSheet
, pour plus de clarté , il est préférable d'être explicite. Mais attention, car certaines Worksheet
méthodes modifient la feuille active.
Set rng = ActiveSheet.Range("A1")
Encore une fois, cela fait référence au classeur actif . À moins que vous ne souhaitiez spécifiquement travailler uniquement avec ActiveWorkbook
ou ThisWorkbook
, il est également préférable d'atténuer une Workbook
variable.
Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")
Si vous ne voulez travailler avec la ActiveWorkbook
, pour plus de clarté , il est préférable d'être explicite. Mais attention, car de nombreuses WorkBook
méthodes changent le livre actif.
Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")
Vous pouvez également utiliser l' ThisWorkbook
objet pour faire référence au livre contenant le code en cours d'exécution.
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")
Un morceau de code courant (mauvais) est d'ouvrir un livre, d'obtenir des données puis de le refermer
C'est mauvais:
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
Et ce serait mieux comme:
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
Passez des plages à vos Sub
s et Function
s en tant que variables de plage:
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
Vous devez également appliquer des méthodes (telles que Find
et Copy
) aux variables:
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
Si vous bouclez sur une plage de cellules, il est souvent préférable (plus rapide) de copier d'abord les valeurs de plage dans un tableau de variantes et de boucler dessus:
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
Ceci est un petit avant-goût de ce qui est possible.
Deux principales raisons pour lesquelles .Select
, .Activate
, Selection
, Activecell
, Activesheet
, Activeworkbook
, etc. doivent être évités
- Cela ralentit votre code.
- C'est généralement la principale cause des erreurs d'exécution.
Comment l'éviter?
1) Travaillez directement avec les objets concernés
Considérez ce code
Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"
Ce code peut également être écrit comme
With Sheets("Sheet1").Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
2) Si nécessaire, déclarez vos variables. Le même code ci-dessus peut être écrit comme
Dim ws as worksheet
Set ws = Sheets("Sheet1")
With ws.Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
Un petit point d'insistance que j'ajouterai à toutes les excellentes réponses données précédemment:
La plus grande chose que vous pouvez probablement faire pour éviter d'utiliser Select est d'utiliser autant que possible des plages nommées (combinées avec des noms de variables significatifs) dans votre code VBA . Ce point a été mentionné ci-dessus, mais il a été un peu passé sous silence; cependant, il mérite une attention particulière.
Voici quelques raisons supplémentaires d'utiliser libéralement les plages nommées, même si je suis sûr que je pourrais penser à plus.
Les plages nommées facilitent la lecture et la compréhension de votre code.
Exemple:
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
Il est assez évident ce que les plages nommées Months
et MonthlySales
contiennent, et ce que fait la procédure.
Pourquoi est-ce important? En partie parce qu'il est plus facile pour les autres de le comprendre, mais même si vous êtes la seule personne qui verra ou utilisera jamais votre code, vous devriez toujours utiliser des plages nommées et de bons noms de variables car vous oublierez ce que vous vouliez en faire un an plus tard, et vous perdrez 30 minutes à comprendre ce que fait votre code.
Les plages nommées garantissent que vos macros ne se cassent pas lorsque (pas si!) La configuration de la feuille de calcul change.
Considérez, si l'exemple ci-dessus avait été écrit comme ceci:
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
Ce code fonctionnera très bien au début - c'est-à-dire jusqu'à ce que vous ou un futur utilisateur décidez "gee wiz, je pense que je vais ajouter une nouvelle colonne avec l'année dans Colonne A
!", Ou mettre une colonne de dépenses entre les mois et des colonnes de ventes ou ajoutez un en-tête à chaque colonne. Maintenant, votre code est cassé. Et parce que vous avez utilisé des noms de variables terribles, il vous faudra beaucoup plus de temps pour comprendre comment le réparer que cela ne devrait prendre.
Si vous aviez utilisé des plages nommées pour commencer, les colonnes Months
et Sales
pourraient être déplacées à votre guise, et votre code continuerait à fonctionner correctement.
Je vais donner la réponse courte puisque tout le monde a donné la longue.
Vous obtiendrez .select et .activate chaque fois que vous enregistrez des macros et les réutilisez. Lorsque vous sélectionnez une cellule ou une feuille, cela la rend simplement active. À partir de là, chaque fois que vous utilisez des références non qualifiées, comme Range.Value
elles utilisent simplement la cellule et la feuille actives. Cela peut également être problématique si vous ne regardez pas où votre code est placé ou si un utilisateur clique sur le classeur.
Ainsi, vous pouvez éliminer ces problèmes en référençant directement vos cellules. Ce qui 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)
Ou tu pourrais
'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"
Il existe diverses combinaisons de ces méthodes, mais ce serait l'idée générale exprimée le plus rapidement possible pour des gens impatients comme moi.
"... et je trouve que mon code serait plus réutilisable si je pouvais utiliser des variables au lieu de fonctions Select."
Bien que je ne puisse penser à rien de plus qu’à une poignée isolée de situations où .Select
serait un meilleur choix que le référencement direct à une cellule, je voudrais soulever la défense Selection
et souligner qu’il ne devrait pas être rejeté pour les mêmes raisons qu’il .Select
faudrait éviter.
Il y a des moments où avoir des sous-routines macro courtes et rapides assignées à des combinaisons de touches de raccourci disponibles en appuyant sur quelques touches permet de gagner beaucoup de temps. Être capable de sélectionner un groupe de cellules pour appliquer le code opérationnel sur fonctionne à merveille lorsqu'il s'agit de données empochées qui ne sont pas conformes à un format de données à l'échelle de la feuille de calcul. De la même manière que vous pouvez sélectionner un groupe de cellules et appliquer un changement de format, la sélection d'un groupe de cellules sur lequel exécuter un code de macro spécial peut être un gain de temps majeur.
Exemples de sous-cadre basé sur la sélection:
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
Le code réel à traiter peut être n'importe quoi, d'une seule ligne à plusieurs modules. J'ai utilisé cette méthode pour lancer de longues routines sur une sélection irrégulière de cellules contenant les noms de fichiers de classeurs externes.
En bref, ne jetez pas en Selection
raison de son association étroite avec .Select
et ActiveCell
. En tant que propriété de feuille de calcul, elle a de nombreux autres objectifs.
(Oui, je sais que cette question portait sur .Select
, Selection
mais je voulais supprimer toutes les idées fausses que les codeurs VBA novices pourraient déduire.)
Éviter Select
et Activate
c'est le mouvement qui vous rend un peu meilleur développeur VBA. En général, Select
et Activate
sont utilisés lorsqu'une macro est enregistrée, ainsi la Parent
feuille de calcul ou la plage est toujours considérée comme active.
Voici comment vous pouvez éviter Select
et Activate
dans les cas suivants:
Ajouter une nouvelle feuille de calcul et copier une cellule dessus:
De (code généré avec l'enregistreur de macros):
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
Lorsque vous souhaitez copier une plage entre des feuilles de calcul:
De:
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")
Utilisation de plages nommées sophistiquées
Vous pouvez y accéder avec []
, ce qui est vraiment beau par rapport à l'inverse. Vérifie toi-même:
Dim Months As Range
Dim MonthlySales As Range
Set Months = Range("Months")
Set MonthlySales = Range("MonthlySales")
Set Months =[Months]
Set MonthlySales = [MonthlySales]
L'exemple ci-dessus ressemblerait à ceci:
Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]
Ne pas copier les valeurs, mais les prendre
Habituellement, si vous le souhaitez select
, vous copiez probablement quelque chose. Si vous n'êtes intéressé que par les valeurs, c'est une bonne option pour éviter de sélectionner:
Range("B1:B6").Value = Range("A1:A6").Value
Essayez également de toujours référencer la feuille de travail
C'est probablement l'erreur la plus courante dans vba . Chaque fois que vous copiez des plages, parfois la feuille de calcul n'est pas référencée et donc VBA considère la mauvaise feuille comme 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
Puis-je vraiment ne jamais utiliser .Select
ou .Activate
pour quoi que ce soit?
- Un bon exemple de cas où vous pourriez être justifié d'utiliser
.Activate
et.Select
c'est quand vous voulez vous assurer qu'une feuille de calcul spécifique est sélectionnée pour des raisons visuelles. Par exemple, que votre Excel s'ouvre toujours avec la feuille de calcul de couverture sélectionnée en premier, sans tenir compte de la feuille ActiveSheet lorsque le fichier a été fermé.
Ainsi, quelque chose comme le code ci-dessous est absolument OK:
Private Sub Workbook_Open()
Worksheets("Cover").Activate
End Sub
Un autre bon exemple est lorsque vous devez exporter toutes les feuilles dans un fichier PDF, comme mentionné dans ce cas - Comment éviter les instructions select / active dans VBA dans cet exemple?
Lorsqu'une commande fonctionne uniquement avec
ActiveWindow
comme ActiveWindow.Zoom ou ActiveWindow.FreezePanes
Veuillez noter que dans ce qui suit, je compare l'approche Select (celle que l'OP veut éviter), avec l'approche Range (et c'est la réponse à la question). Alors ne vous arrêtez pas de lire lorsque vous voyez le premier Select.
Cela dépend vraiment de ce que vous essayez de faire. Quoi qu'il en soit, un exemple simple pourrait être utile. Supposons que vous souhaitiez définir la valeur de la cellule active sur "foo". En utilisant ActiveCell, vous écririez quelque chose comme ceci:
Sub Macro1()
ActiveCell.Value = "foo"
End Sub
Si vous souhaitez l'utiliser pour une cellule qui n'est pas active, par exemple pour "B2", vous devez d'abord la sélectionner, comme ceci:
Sub Macro2()
Range("B2").Select
Macro1
End Sub
En utilisant Ranges, vous pouvez écrire une macro plus générique qui peut être utilisée pour définir la valeur de n'importe quelle cellule que vous voulez sur ce que vous voulez:
Sub SetValue(cellAddress As String, aVal As Variant)
Range(cellAddress).Value = aVal
End Sub
Ensuite, vous pouvez réécrire Macro2 comme:
Sub Macro2()
SetCellValue "B2", "foo"
End Sub
Et Macro1 comme:
Sub Macro1()
SetValue ActiveCell.Address, "foo"
End Sub
Indiquez toujours le classeur, la feuille de calcul et la cellule / plage.
Par exemple:
Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)
Parce que les utilisateurs finaux cliquent toujours simplement sur les boutons et dès que le focus se déplace hors du classeur, le code veut travailler avec, les choses tournent complètement mal.
Et n'utilisez jamais l'index d'un classeur.
Workbooks(1).Worksheets("fred").cells(1,1)
Vous ne savez pas quels autres classeurs seront ouverts lorsque l'utilisateur exécutera votre code.
Ces méthodes sont plutôt stigmatisées, prenant donc la tête de Vityata et Jeeped pour tracer une ligne dans le sable:
Appel .Activate
, .Select
, Selection
, ActiveSomething
méthodes / propriétés
Fondamentalement, parce qu'ils sont appelés principalement pour gérer les entrées utilisateur via l'interface utilisateur de l'application. Comme ce sont les méthodes appelées lorsque l'utilisateur manipule des objets via l'interface utilisateur, ce sont celles enregistrées par le macro-enregistreur, et c'est pourquoi les appeler est soit cassant, soit redondant dans la plupart des situations: vous n'avez pas à sélectionner un objet afin d'effectuer une action avec Selection
juste après.
Cependant, cette définition règle les situations pour lesquelles elles sont appelées:
Quand appeler .Activate
, .Select
, .Selection
, .ActiveSomething
méthodes / propriétés
Fondamentalement, lorsque vous attendez de l' utilisateur final qu'il joue un rôle dans l'exécution.
Si vous développez et attendez de l'utilisateur qu'il choisisse les instances d'objet que votre code doit gérer, alors .Selection
ou .ActiveObject
sont appropriés.
D'autre part, .Select
et .Activate
sont utiles lorsque vous pouvez déduire la prochaine action de l'utilisateur et que vous voulez que votre code guide l'utilisateur, lui faisant éventuellement gagner du temps et des clics de souris. Par exemple, si votre code vient de créer une toute nouvelle instance d'un graphique ou une mise à jour, l'utilisateur peut vouloir l'extraire, et vous pouvez appeler .Activate
dessus ou sa feuille pour économiser à l'utilisateur le temps de le chercher; ou si vous savez que l'utilisateur devra mettre à jour certaines valeurs de plage, vous pouvez sélectionner cette plage par programme.
À mon humble avis de l' utilisation .select
vient des gens qui comme moi ont commencé à apprendre VBA par nécessité à travers l' enregistrement des macros, puis en modifiant le code sans se rendre compte que .select
et après selection
est juste un moyen-hommes inutiles.
.select
can be avoided, as many posted already, by directly working with the already existing objects, which allows various indirect referencing like calculating i and j in a complex way and then editing cell(i,j), etc.
Otherwise, there is nothing implicitly wrong with .select
itself and you can find uses for this easily, e.g. I have a spreadsheet that I populate with date, activate macro that does some magic with it and exports it in an acceptable format on a separate sheet, which, however, requires some final manual (unpredictable) inputs into an adjacent cell. So here comes the moment for .select
that saves me that additional mouse movement and click.
To avoid using the .Select
method, you can set a variable equal to the property that you want.
► For instance, if you want the value in Cell A1
you could set a variable equal to the value property of that cell.
- Example
valOne = Range("A1").Value
► For instance, if you want the codename of 'Sheet3you could set a variable equal to the
Codename` property of that worksheet.
- Example
valTwo = Sheets("Sheet3").Codename
I noticed that none of these answers mention the .Offset Property. This also can be used to avoid using the Select
action when manipulating certain cells, particularly in reference to a selected cell (as the OP mentions with ActiveCell
).
Here are a couple examples.
I will also assume the "ActiveCell" is J4.
ActiveCell.Offset(2, 0).Value = 12
- This will change the cell
J6
to be a value of 12 - A minus -2 would have referenced J2
ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)
- This will copy the cell in
k4
toL4
. - Note that "0" is not needed in the offset parameter if not needed (,2)
- Similar to the previous example a minus 1 would be
i4
ActiveCell.Offset(, -1).EntireColumn.ClearContents
- This will clear values in all cells in the column k.
These aren't to say they are "better" than the above options, but just listing alternatives.
How to avoid copy-paste?
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.