What is the difference between the VBA code wb.Sheets(1).Cells.Select and wb.Sheets(1).Activate?
Difference between select is that you can select several objects at once. Objects that are selected are also placed in the Selection object which you can use methods on. Unless you are selecting multiple objects, selecting (say, a cell) activates the object.
Activate just simply makes the object the active object.
Best way to think of it is "many cells can be selected, but only one may be the active cell at any given time."
Note: They both have one thing in common - they are rarely ever needed and they do generally don't do anything but slow your code down. You can work directly on an object without selecting or activating it and it's best practice not to use these unless needed.
Here is an explanation from MSDN
You first example wb.Sheets(1).Cells.Select allows you to select multiple cells
The second wb.Sheets(1).Activate makes the sheet active.
There are lots of resources out there to help with Excel VBA.
http://www.excel-vba.com/index.htm#Tutorial%20on%20Excel%20Macros
http://www.excel-vba-easy.com/
http://www.functionx.com/vbaexcel/
The first selects all cells on the first sheet of the workbook wb. It will fail if the sheet is not active.
The second just activates the first sheet of the workbook wb. It does not alter the selection or activecell on that sheet, and in some cases there may be no selected range or activecell (eg. if there's an object on the sheet which is currently selected).
Select - "Selects" Cell(s)
Activate - "Activates" a sheet (kind of like saying to focus on a sheet)
Sometimes u need to specifically ACTIVATE the sheet, in order to make a SELECT
I found this question while searching, I had the same question. Here is something I noticed:
Sub Transfer(x As Long)
Dim Rng, ID as Range
Dim i, j, n As Long
Worksheets(5).Activate
n = Worksheets(5).Range(Range("I88"), Range("I88").End(xlToRight)).Count
Worksheets(x).Select
Set Rng = Worksheets(3).UsedRange.Find("Element", LookIn:=xlValues).Offset(1, 1)
Set ElemID = Range(ElemRng.Offset(0, -1), ElemRng.Offset(0, -1).End(xlDown))
Set ElemRng = Worksheets(3).Range(ElemRng, ElemRng.End(xlToRight))
End Sub
I found that I HAD to put the worksheet.activate (or select) in or the code would run into:
Run-time error: '1004'
Application-defined or object-defined error
Activate is often used for Sheets for Example.
The Active sheet wil be shown on the screen... therfore there can only be one active sheet
Select though is can be used for multiple Cells for Example.
Range(A1:B3).Select will select multiple cell which is'nt possible with activate
Related
This is the code I have in a [very involved] spreadsheet someone made at work:
Sub ClearSheet()
'
' Macro5 Macro
'
'
Range("E9,E2:F7,C14:I39,Q41:Q55,N14:N39,N41:N55").Select
Range("Q14").Activate
Range("E9,E2:F7,C14:I39,C41:I55,Q41:Q55,N14:N39,N41:N55,L41:L55").Select
Range("Q41").Activate
Selection.ClearContents
I have never so much as glanced at an excel macro before, so I had to look some things up. I get that the first range is selected and then Q14 becomes the active cell. Then that is done again, with some overlapping sections, and Q41 is made into the active cell. All to have the selections just be cleared out. I'm sure this is a simple question but I don't understand what the point is of the .Activates, or why someone would separate the sections that need to be cleared into two separate segments? From my very limited understanding, I thought Activate was something like focus, where that is now that cell that has focus for ease of use on the users side. But what good is that if the focus changes from the first cell to the second cell in a millisecond?
All I know is that I need these cells:
E9,E2:F7,C14:I39,N14:N39,C41:I55,L41:L55,N41:N55,Q41:Q55
to clear out when this code is run, and if this code is doing something in addition to that, what is it?
Is this just poorly written or am I too ignorant to understand? ~the novel~
Use
Range("E9,E2:F7,C14:I39,N14:N39,C41:I55,L41:L55,N41:N55,Q41:Q55").ClearContents
Better still specify the workbook and worksheet to do this in e.g.
ThisWorkbook.Worksheets("Sheet1").Range("E9,E2:F7,C14:I39,N14:N39,C41:I55,L41:L55,N41:N55,Q41:Q55").ClearContents
Using sheet 1 as an example. You want to be sure to be in the right sheet before clearing stuff out. If you don't specify, and leave as just range, then the currently Active sheet is used.
In the code you talked about the each selection was shifting focus from the prior making the prior selections redundant.
Using Select, in particular, is not generally a good thing, it means 'touching' the sheet which incurs potentially unnecessary performance overhead.
As mentioned in comments, and indicated by ' Macro5 Macro, this is, at least in part, likely all, macro generated code. Macro meaning "many". Many instructions in this case. The macro recorder is verbose to say the least. It records everything your are doing including scrolling, mistakes in range selections etc. It is a good learning tool, and can often give useful insights into some objects and methods. The valuable skill is learning which elements to keep and how to turn this verbose code into structured programming.
The way you interpret Select and Activate is correct, one is for the actual selection and the other is somewhat to focus.
Select as the method name suggest selects the object. This method is not limited to Range Objects alone but is shared by most of the objects in Excel. Some of the examples:
Range("A1").Select '/* selecting a Range Object */
Worksheets("Sheet1").Select '/* selecting a Sheet Object */
Activate on the other hand works when you already selected an object.
Activates a single cell, which must be inside the current selection. To select a range of cells, use the Select method.
So what happens when you activate a cell not in the current selection?
It becomes the selected cell and as you've said, Excel executes the Select first and then the Activate in mili or nano or pico seconds (God knows how fast) interval.
In Range Objects the use of Select and Activate is almost interchangeable. But you have to take note that there will be difference always with Selection and ActiveCell. For example:
Range("A1:B10").Select
Range("B5").Activate
Debug.Print Selection.Address
Debug.Print ActiveCell.Address
This means that you can actually do stuff (e.g. format, clear, add formula, add text etc.) on all cells you activate within the current selection but still preserves what Selection object points to.
There are cases that activating the object is vital. For example you want to select multiple worksheets like below and then select Range("A1") of Sheet3.
Worksheets(Array("Sheet1", "Sheet3", "Sheet5")).Select
Worksheets("Sheet3").Activate '/* vital */
Worksheets("Sheet3").Range("A1").Select
Above is the correct select command for multiple worksheet selection and selecting a range within 1 of the worksheets selected. But without the Activate part, there is a chance that it will return:
Run-time error '1004': Select method of Range class failed
because the first sheet in the array will always be the activated sheet object after the select. Now, how to avoid this troubles? Simple, avoid using select and activate. ~the novel sequel~
This is actually an improvement for this previous topic.
Context:
Excel 2003, Windows 7 Professional SP1.
Working on workbook A, which contains a cell with conditional formatting calling a personal function. This function refers to a defined name of workbook A.
Workbook B is opened or edited (not only activated). It can be any workbook.
We activate back workbook A.
Problem:
The conditional formatting causes various bugs if workbook B's window overlaps workbook A's. In other words, when at some point workbook A gets behind workbook B.
Depending on the window state (whether Excel is in full screen or not, whether ActiveWindow.WindowState = xlNormal or xlMaximized, whether the window is narrow or wide ...), the bugs can be :
Mainly: cells calling personal (volatile) functions that refer to defined names don't calculate when switching back to workbook A. This is a huge problem, as I need to force calculation with Ctrl+Alt+F9.
Display bugs often occur, notably when workbooks A and B are floating next to each other, overlapping each other. Cell content vanish, ghosts cells of the ones with conditional formatting appear, the screen freezes, window border trails (W98 style) are displayed when trying to move around one of the workbooks ...
In Workbook_Activateof workbook A, breakpoints don't stop the code (though debug.print and MsgBox work) and you can't use Application or ActiveWindow methods. Application.CalculateFull sometimes causes all the cells' content to disappear until they are selected (using Ctrl+A, for example).
How to solve or avoid this problem?
I will answer to myself below, if it can be of some interest for anyone!
Solution 1:
Just don't use personal functions referring to defined cells names in conditional formatting formulas.
This solution solves every problem, but it's not acceptable when you have to have complex conditional formatting.
Solution 2:
Bug sample
Bug sample (solved)
Create a named cell anywhere in workbook A, for example call it "CondFormat". Set its value to "TRUE".
This will be the boolean driving the call of personal functions in your conditional formatting formulas.
Edit every conditional formatting this way:
=MyFunctionWithCellNames($A1)
becomes:
=IF(CondFormat,MyFunctionWithCellNames($A1))
Automatically toggle the boolean when you activate or deactivate the workbook:
Private Sub Workbook_Activate()
[CondFormat] = True
End Sub
Private Sub Workbook_Deactivate()
ThisWorkbook.Names("CondFormat").RefersToRange = False
End Sub
Note 1: sometimes, [CondFormat] isn't toggled when leaving the workbook. The ThisWorkbook.Names syntax makes it work all the time.
Note 2: we have to use one of the cells for the boolean CondFormat, because only macros can access to VBA global variables.
Note 3: I spent a lot of time figuring this out, I hope it will be useful for others. I think that most problems with conditional formatting can only be solved this way in Excel 2003, as Sheet.EnableFormatConditionsCalculation method only appeared in Excel 2007.
I am working on an excel document at the moment and everything is turning out quite nicely. However, I am coming down to the very last issue that I am having a problem resolving: being able to sort my columns in ascending/descending order while the worksheet is protected and the column headers are locked. I will state some facts about my worksheet first, the goal that I am trying to accomplish, then possible solutions that I have researched and why those solutions do not seem to apply to my situation.
First, I am NOT using an excel table object (just plain
rows/columns).
The top row has AutoFilter applied (to work as column headers).
All of the cells in the worksheet are unlocked, EXCEPT for the
entire first row which is locked (aka, the column headers).
The worksheet will be protected.
I do NOT want users to be able to edit data in the first row (this
is important, these must not be editable no matter what).
For my protected sheet settings, I have "Select locked
cells","Select unlocked cells","Insert rows","Delete rows","Sort",
and "AutoFilter" checked.
I am using VBA for my worksheet.
I am using Excel 2013
Now, assuming the worksheet is protected, users are currently able to use the AutoFilter at the top to actually "filter" the data as intended. The issue is whenever they try to "sort" the data in ascending/descending order that I get an error saying that you must unprotect the sheet first.
After researching I have seen that this is due to the fact that when you sort, the AutoFilter automatically counts the column header as part of the range being sorted... but because this column header (row 1) is locked, it is causing this error. However, this row HAS to be locked, my VBA code specifically reads the values in these column headers and under no circumstances can they be changed.
So filtering works just fine, it is just the sorting I am trying to figure out now. My "ideal" solution would be to somehow capture an event when a user clicks on the AutoFilter arrow and selects "Sort" where I can then, in VBA, unprotect the sheet, sort according to their selection, then protect the sheet again. However, again upon research, it seems that there really isn't an option when it comes to an event for this AutoFilter button (I could be wrong, sometimes it can be confusing reading other's suggestions).
I am hoping someone out there can help me out with this situation, I would also LIKE to avoid using an excel table object, however if it is the only solution that works that meets all my above criteria then so-be-it.
Thanks in advance for your help.
If you already use VBA, you can plug this code into the Sheet module. This assumes the headers are in row 1. Change to suit.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("1:1")) Is Nothing Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub
The sheet now does not need to be protected.
Borrowing a bit from #Teylyn's and adapted it to disallow selection of the header row, when it is selected, it selects the cell below it directly and displays an error message. The code sits in the sheet module, if it needs to be applied to more sheets, it may be better to use Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range), in that case, replace all instances of Me with Sh in the code below.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(Target, Me.Range("1:1")) Is Nothing Then
Target.Offset(1, 0).Select
MsgBox "You cannot select or edit the headerrow, please use the autofilter button to sort and filter.", vbCritical, "Invalid Selection"
End If
End Sub
Note
Unlocking the cells which is required for the sorting and then allowing unlocked cells to be selected when protecting the worksheet, which is needed to be able to edit the data, makes the worksheet protection effectively useless.
Also wit the code above, there is still a loophole through which cells can be edited. If you select an allowed cell, drag it to the header row, and choose to replace the data in the cell then the header cell to which the allowed cell was moved is selected and editable.
End of note
Select the data range which needs to be sorted and unlock the cells.
When protecting the worksheet, be sure to allow
sort
autofilter
To prevent users from changing the cell contents, disallow the selection of unlocked cells.
This is one that's been killing me and I've tried almost every solution on the Internet.
Here's background. I have an HR model that has each department broken out on separate tabs. I want to run an extract from our payroll system each payroll run and send highlight any updates individually. If someone's title or salary or status changes, I want to have that called out by highlighting the cell.
Each tab uses an INDEX/MATCH lookup to the extract tab to pull in the current information. What I want is if any value changes or is new(new hire, for example), highlight the cells.
I've played with Worksheet_Calculate and Worksheet_Change to no avail. Worksheet_Change doesn't fire because I'm not making the change directly on the sheet and Worksheet_Calculate doesn't have the Target object for to reference. I've tried the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim updatedCell As Range
Set updatedCell = Range(Target.Dependents.Address)
If Not Intersect(updatedCell, Range("A:A")) Is Nothing Then
updatedCell.Interior.ColorIndex = 3
End If
End Sub
The range I actually need evaluated is A7:R104 but I've been trying to get anything to work when linked to another sheet.
This works fine if formula of target cell is pointing to another cell on same sheet. The moment you point to one on another sheet it doesn't work. I've tried most of the solutions on here with no success. I've even tried putting the Worksheet_Change on the extract sheet and see if I can trigger it that way with no luck.
Is there a recommended solution to triggering a change to a cell for a formula linked to another sheet?
so I just saw this post, I don't know if you've found the solution or are still looking, but:
if you select a cell in sheet 3, you can then go to the home tab, go to "conditional formatting" -highlight cell rules - more rules (at the bottom) - and "use formulas to determine which cells to format" and then put your cursor in the formula box. now, select a cell in sheet 1 (click the sheet1 tab, and click a cell) and you'll notice it should populate the address for sheet1, and the cell u selected. now type <> after that cells address, then select sheet2 and a cell. then click format, and choose a fill color. then ok. if you go to conditional formatting and manage rules it will show there the rule / formula and which cells it applies to.
doing this i was able to select cell D10 in sheet 3, and make it an ugly green if cells in sheet1 and 2 didnt match (I picked which cells) you can also select a range of cells.
thusly, you can apply this rule to whatever dells you want, and if you record a macro of you setting this conditional formatting, you can manitpulate that macro to apply it to a bunch of different cells, and change the ranges. (using loops / variables)
I have data from like A1:Z50 but I want to delete only A5:X50 using VBA
(I think it will be a lot faster than dragging the whole cell or using clickA5+shift+clickX50+delete).
How can I do this ?
And then, how to lock the cell to prevent it from getting fixed or cleared ?
You could define a macro containing the following code:
Sub DeleteA5X50()
Range("A5:X50").Select
Selection.ClearContents
end sub
Running the macro would select the range A5:x50 on the active worksheet and clear all the contents of the cells within that range.
To leave your formulas intact use the following instead:
Sub DeleteA5X50()
Range("A5:X50").Select
Selection.SpecialCells(xlCellTypeConstants, 23).Select
Selection.ClearContents
end sub
This will first select the overall range of cells you are interested in clearing the contents from and will then further limit the selection to only include cells which contain what excel considers to be 'Constants.'
You can do this manually in excel by selecting the range of cells, hitting 'f5' to bring up the 'Go To' dialog box and then clicking on the 'Special' button and choosing the 'Constants' option and clicking 'Ok'.
Try this
Sheets("your sheetname").range("A5:X50").Value = ""
You can also use
ActiveSheet.range
Not sure its faster with VBA - the fastest way to do it in the normal Excel programm would be:
Ctrl-G
A1:X50 Enter
Delete
Unless you have to do this very often, entering and then triggering the VBAcode is more effort.
And in case you only want to delete formulas or values, you can insert Ctrl-G, Alt-S to select Goto Special and here select Formulas or Values.