I've heard much about the understandable abhorrence of using .Select
in Excel VBA, but am unsure of how to avoid using it. I am finding that my code would be more re-usable if I were able to use variables instead of Select
functions. However, I am not sure how to refer to things (like the ActiveCell
etc.) if not using Select
.
I have found this article on ranges and this example on the benefits of not using select but can't find anything on how?
While I cannot think of any more than an isolated handful of situations where
.Select
would be a better choice than direct cell referencing, I would rise to the defense ofSelection
and point out that it should not be thrown out for the same reasons that.Select
should be avoided.There are times when having short, time-saving macro sub routines assigned to hot-key combinations available with the tap of a couple of keys saves a lot of time. Being able to select a group of cells to enact the operational code on works wonders when dealing with pocketed data that does not conform to a worksheet-wide data format. Much in the same way that you might select a group of cells and apply a format change, selecting a group of cells to run special macro code against can be a major time saver.
Examples of Selection-based sub framework:
The actual code to process could be anything from a single line to multiple modules. I have used this method to initiate long running routines on a ragged selection of cells containing the filenames of external workbooks.
In short, don't discard
Selection
due to its close association with.Select
andActiveCell
. As a worksheet property it has many other purposes.(Yes, I know this question was about
.Select
, notSelection
but I wanted to remove any misconceptions that novice VBA coders might infer.)These methods are rather stigmatized, so taking the lead of @Vityata and @Jeeped for the sake of drawing a line in the sand:
Why not call
.Activate
,.Select
,Selection
,ActiveSomething
methods/propertiesBasically because they're called primarily to handle user input through the Application UI. Since they're the methods called when the user handles objects through the UI, they're the ones recorded by the macro-recorder, and that's why calling them is either brittle or redundant for most situations: you don't have to select an object so as to perform an action with
Selection
right afterwards.However, this definition settles situations on which they are called for:
When to call
.Activate
,.Select
,.Selection
,.ActiveSomething
methods/propertiesBasically when you expect the final user to play a role in the execution.
If you are developing and expect the user to choose the object instances for your code to handle, then
.Selection
or.ActiveObject
are apropriate.On the other hand,
.Select
and.Activate
are of use when you can infer the user's next action and you want your code to guide the user, possibly saving him some time and mouse clicks. For example, if your code just created a brand new instance of a chart or updated one, the user might want to check it out, and you could call.Activate
on it or its sheet to save the user the time searching for it; or if you know the user will need to update some range values, you can programatically select that range.Quick Answer:
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.valOne = Range("A1").Value
► For instance, if you want the codename of 'Sheet3` you could set a variable equal to the codename property of that worksheet.
valTwo = Sheets("Sheet3").Codename
I hope that helps. Let me know if you have any questions.
Working with .Parent feature. This example shows how setting only one myRng reference enables dynamic access to the entire environment with no .Select, .Activate, .Activecell, .ActiveWorkbook, .ActiveSheet and so on. (There's no genereic .Child feature)
One small point of emphasis I'll add to all the excellent answers given above:
Probably the biggest thing you can do to avoid using Select is to as much as possible, use named ranges (combined with meaningful variable names) in your VBA code. This point was mentioned above, but glossed over a bit; however, it deserves special attention.
Here are a couple additional reasons to make liberal use of named ranges though I am sure I could think of more.
Named ranges make your code easier to read and understand.
Example:
It is pretty obvious what the named ranges
Months
andMonthlySales
contain, and what the procedure is doing.Why is this important? Partially because it is easier for other people to understand it, but even if you are the only person who will ever see or use your code, you should still use named ranges and good variable names because YOU WILL FORGET what you meant to do with it a year later, and you will waste 30 minutes just figuring out what your code is doing.
Named ranges ensure that your macros do not break when (not if!) the configuration of the spreadsheet changes.
Consider, if the above example had been written like this:
This code will work just fine at first - that is until you or a future user decides "gee wiz, I think I'm going to add a new column with the year in Column
A
!", or put an expenses column between the months and sales columns, or add a header to each column. Now, your code is broken. And because you used terrible variable names, it will take you a lot more time to figure out how to fix it than it should take.If you had used named ranges to begin with, the
Months
andSales
columns could be moved around all you like, and your code will continue working just fine.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 withActiveCell
).Here are a couple examples.
I will also assume the "ActiveCell" is J4.
ActiveCell.Offset(2, 0).Value = 12
J6
to be a value of 12ActiveCell.Offset(0,1).Copy ActiveCell.Offset(,2)
k4
toL4
.i4
ActiveCell.Offset(, -1).EntireColumn.ClearContents
These aren't to say they are "better" than the above options, but just listing alternatives.