|
By setting the Replace argument to False one can add to the
existing selection! The code sample below selects both
the datasheet Sheet2 and the chart sheet Chart1 and copies them to a
new workbook.
Sheets("Sheet2").Select
Sheets("Chart1").Select False
ActiveWindow.SelectedSheets.Copy
As has been noted elsewhere, selecting and activating objects is
a step of last resort. Whenever possible, it is preferred that
one work without selecting and activating sheets. We will see
how to do that next.
Next, we convert our above code sample to use an array.
Since this will be a building block for the next case where the
names are not known in advance, we will use an array data structure.
Option Explicit
Option Base 0
Sub testDynamicSheetArray()
Dim x(1)
x(0) = "Sheet2": x(1) = "Chart1"
Sheets(x).Copy
End Sub
Finally, we need to figure out a way to work with sheets whose
names we don't know up front. In fact, we might not even know
how many sheets we want to work with.
Next, we look at how we can operate on sheets without knowing
their names up front. Suppose we want to copy to a new
workbook all the sheets in the active workbook that have a left
parenthesis in their respective names. The code below uses an
array to store the names of interest and then it carries out the
copy in one step.
The handling of the array SheetsFound probably deserves
some clarification. Except at the very end, it is always one
larger than the amount of valid data in it. Before the first
iteration of the For Each aSheet loop it has one element
(index zero) that contains nothing. Whenever a sheet of
interest is found, its name is entered in the empty element and
the array is resized to be one larger. That means that once
again the array has one element that is empty. Hence, when
all iterations of the loop are complete, the array will still have
one element too many. Consequently, the final ReDim trims
the array by one.
Option Explicit
Option Base 0
Sub testDynamicSheetCopy()
Dim aSheet As Object, SheetsFound()
ReDim SheetsFound(0)
For Each aSheet In ActiveWorkbook.Sheets
If InStr(1, aSheet.Name, "(") > 0 Then
SheetsFound(UBound(SheetsFound)) = aSheet.Name
ReDim Preserve SheetsFound(UBound(SheetsFound) + 1)
End If
Next aSheet
ReDim Preserve SheetsFound(UBound(SheetsFound) - 1)
Sheets(SheetsFound).Copy
End Sub
One of the features that Microsoft added to Excel is this ability
to edit multiple worksheets simultaneously. Using the
categories mentioned in the introduction, this capability falls
under the "convenience" category rather than one where behavior is
altered.
Together with what Microsoft calls 3D formulas, this capability
is something that doesn't naturally fit in with the Excel object
model. Consequently, Microsoft made some compromises within
the model. The standard object model gets sidestepped in these
cases and we are forced to use the selection and the
activecell objects.
The code that the macro recorder generates to work on Sheet1 and
Sheet2 simultaneously is shown below. The first sample creates
the sheet group and changes just one cell (A1). The second
code sample changes a group of cells (A2:B3).
Sheets(Array("Sheet2", "Sheet1")).Select
Sheets("Sheet2").Activate
Range("A1").Select
ActiveCell.FormulaR1C1 = "14"
Range("A2:B3").Select
Selection.FormulaR1C1 = "16"
Essentially, if we were to try and do this through code, we would
have to select the specific cell in one of the selected sheets and
then work with the Selection object.
Sub testDynamicSheetEdit()
Dim aSheet As Object, SheetsFound()
ReDim SheetsFound(0)
For Each aSheet In ActiveWorkbook.Sheets
If InStr(1, aSheet.Name, "(") > 0 Then
SheetsFound(UBound(SheetsFound)) = aSheet.Name
ReDim Preserve SheetsFound(UBound(SheetsFound) + 1)
End If
Next aSheet
ReDim Preserve SheetsFound(UBound(SheetsFound) - 1)
Sheets(SheetsFound).Select
Sheets(SheetsFound(0)).Activate
Range("A2:B3").Select
Selection.FormulaR1C1 = "22"
End Sub
There doesn't appear to be anyway to avoid the activation and
selection. For example, the following code segment generates
the runtime error "Object does not support this property or method."
Sheets(SheetsFound).Range("a2:b3").Value = "24"
The following, on the other hand, only changes the sheet
identified in SheetsFound(0)
Sheets(SheetsFound).Select
Sheets(SheetsFound(0)).Range("a2:b3").Value = "24"
In several of the above examples, we used the construct Sheets(
{some array} ). It is important to note that if the array were
never initialized, Excel/VBA will not gracefully handle what is
clearly an error. Instead Excel will crash! The trivial
example below is one such instance.
Sub crashExcel()
Dim x()
Sheets(x).Copy
End Sub
|