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~
Related
I am trying to open multiple webpage tab from my selected cells. I would like to find the selected cell (based on the mouse) starting and ending row and column information for further use of vba macro.
Thanks in advance...
You can do this:
x = ActiveCell.Address
MsgBox (x)
but really, you should try to avoid using selection where possible. The reason for this is because users can (and I've found, will) click in to other spreadsheets as the code is running and so what you have intended as the selection, may no longer be the actual selection. It also affects the longevity of the code because it's much more difficult to fix if something breaks.
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.
Some of your folks advocate not using ActivateSheet. So how do I get the name of the active worksheet?
You could use Selection.Parent.Name However, that is even worse.
One reason to not use Selection or ActiveSheetis that while debugging, you might inspect other sheets or select other cells, and if you then continue with F5 or F8, you will work on other data than foreseen.
But if the action taken by your code SHOULD depend on which sheet is currently active, just use ActiveSheet. (If you need it at the end of a Subroutine, or if you need it twice, however, consider assigning it to a variable at the beginning.
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
I am new to programming in Excel. I have done very little Visual Basic. What I would like to do is check a column on one sheet in Excel and compare all the values to a column in a different sheet in Excel. Now the problem is, is it possible that when i click on one of the cells it is "linked" to the other and takes me to the matching cell. I would like to have this implemented into the spread sheet and not be a "macro". If anyone can help it would be much appreciated.
"macro" and "implementation in spread sheet" is nearly the same. the macro is, depending on how you do it, stored in the spreadsheet-file (.xls)
you can get the content of a cell by reading
Range("A1").Value // Any cell-reference is valid here.
If you want to read an entire column, you need to use some kind of loop.
the linking you're talking about could be done with the event Worksheet.SelectionChange. e.g. following skeleton:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
you may now fill what should happen when the selection has changed. With Target.Column and Target.Row you may read the row and do the appropriate tests.
You can switch the View on a special Sheet using the Worksheet.Activate-Method which brings on top the worksheet you call the method on.
hope this clarifies a bit... if you need details, i will do some research...
regards