Avoiding select while referring to column by number [duplicate] - vba

I'm trying to move some data from one workbook into another by assigning the values from one range to another. When I use the normal Range syntax to specify the destination range (Range("A1:B2")) my code works, but if I try to use the Range, Cells syntax (Range(Cells(1,1),Cells(2,2))) my code doesn't work.
I activate the destination workbook (ActiveWorkbook) and have the code running in the source workbook (ThisWorkbook).
This code works:
ActiveWorkbook.Worksheets(1).Range("A1:B2").Value _
= ThisWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value
But This code does not:
ActiveWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value _
= ThisWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value
The error I get is Run-time error '1004': Applicaton-defined or object-defined error.
Does anyone know why using the cells object is causing me problems, or if there is some other problem I'm not aware of?

The problem is that Cells is unqualified, which means that the sheet to which those cells refer is different depending on where your code is. Any time you call Range or Cells or Rows or UsedRange or anything that returns a Range object, and you don't specify which sheet it's on, the sheet gets assigned according to:
In a sheet's class module: that sheet regardless of what's active
In any other module: the ActiveSheet
You qualify the Range reference, but the Cells reference is unqualified and is likely pointing to the Activesheet. It's like writing
ThisWorkbook.Worksheets(1).Range(ActiveSheet.Cells(1, 1), ActiveSheetCells(2, 2)).Value
which of course doesn't make any sense unless ThisWorkbook.Worksheets(1) happens to be active. I often like to use a With block so that I make sure everything is fully qualified.
With Sheets(1)
.Range(.Cells(1,1), .Cells(2,2)).Value = "something"
End With
But you refer to two different sheets, so you'll be better off using short sheet variables like:
Dim shSource As Worksheet
Dim shDest As Worksheet
Set shSource = ThisWorkbook.Worksheets(1)
Set shDest = Workbooks("myBook").Worksheets(1)
shDest.Range(shDest.Cells(1, 1), shDest.Cells(2, 2)).Value = _
shSource.Range(shSource.Cells(1, 1), shSource.Cells(2, 2)).Value
But really, if you're going to hardcode the Cells arguments, you could clean that up like
shDest.Cells(1, 1).Resize(2, 2).Value = shSource.Cells(1, 1).Resize(2, 2).Value

Related

Why do I need to activate the sheet before using it [duplicate]

I'm trying to move some data from one workbook into another by assigning the values from one range to another. When I use the normal Range syntax to specify the destination range (Range("A1:B2")) my code works, but if I try to use the Range, Cells syntax (Range(Cells(1,1),Cells(2,2))) my code doesn't work.
I activate the destination workbook (ActiveWorkbook) and have the code running in the source workbook (ThisWorkbook).
This code works:
ActiveWorkbook.Worksheets(1).Range("A1:B2").Value _
= ThisWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value
But This code does not:
ActiveWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value _
= ThisWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value
The error I get is Run-time error '1004': Applicaton-defined or object-defined error.
Does anyone know why using the cells object is causing me problems, or if there is some other problem I'm not aware of?
The problem is that Cells is unqualified, which means that the sheet to which those cells refer is different depending on where your code is. Any time you call Range or Cells or Rows or UsedRange or anything that returns a Range object, and you don't specify which sheet it's on, the sheet gets assigned according to:
In a sheet's class module: that sheet regardless of what's active
In any other module: the ActiveSheet
You qualify the Range reference, but the Cells reference is unqualified and is likely pointing to the Activesheet. It's like writing
ThisWorkbook.Worksheets(1).Range(ActiveSheet.Cells(1, 1), ActiveSheetCells(2, 2)).Value
which of course doesn't make any sense unless ThisWorkbook.Worksheets(1) happens to be active. I often like to use a With block so that I make sure everything is fully qualified.
With Sheets(1)
.Range(.Cells(1,1), .Cells(2,2)).Value = "something"
End With
But you refer to two different sheets, so you'll be better off using short sheet variables like:
Dim shSource As Worksheet
Dim shDest As Worksheet
Set shSource = ThisWorkbook.Worksheets(1)
Set shDest = Workbooks("myBook").Worksheets(1)
shDest.Range(shDest.Cells(1, 1), shDest.Cells(2, 2)).Value = _
shSource.Range(shSource.Cells(1, 1), shSource.Cells(2, 2)).Value
But really, if you're going to hardcode the Cells arguments, you could clean that up like
shDest.Cells(1, 1).Resize(2, 2).Value = shSource.Cells(1, 1).Resize(2, 2).Value

Error 1004 - Opening and activating workbooks

I have some issues while trying to copy/paste data between workbooks. I need to extract data from two different workbooks (A & B) to put it in a third one.
Since A & B have the exact same structure, I use the same code for both of them. However it works for A and I've got an error 1004 for B.
It seems that it happens when you do not specify the parent workbook/worksheet properly but I don't think this is the issue here since the code works for A.
If someone has an insight on this matter, I'm all ears!
Thank you for your help!
CH
Sub Data_Extraction()
Dim wb As Workbook, wba As Workbook, wbb As Workbook
Set wb = ActiveWorkbook
Set wba= Workbooks.Open("D:\xxx\A.xlsx")
Set wbb= Workbooks.Open("D:\xxx\B.xlsx")
Dim wsa As Worksheet, wsb As Worksheet
Set wsa = wb.Worksheets("a")
Set wsb = wb.Worksheets("b")
'I use a named variable here
X = Range("X")
If X=2 Then
''We fill the tab a''
For i = 9 To 400
wba.Activate
If wba.Worksheets("a").Cells(i, 2).Value = 5 Then
wba.Worksheets("a").Range(Cells(i, 1), Cells(i, 8)).Copy
wb.Activate
wsa.Range(Cells(7, 2), Cells(7, 9)).PasteSpecial Paste:=xlPasteValues
wsa.Range("B7").EntireRow.Insert
End If
Next i
''We fill the tab b''
For i = 9 To 400
wbb.Activate
If wbb.Worksheets("b").Cells(i, 2).Value = 5 Then
wbb.Worksheets("b").Range(Cells(i, 1), Cells(i, 8)).Copy
wb.Activate
wsb.Range(Cells(7, 2), Cells(7, 9)).PasteSpecial Paste:=xlPasteValues
wsb.Range("B7").EntireRow.Insert
End If
Next i
End If
End Sub
In lots of cases when you use Excel methods like protect/unprotect copy/paste, you should try to mimick as close as possible the configuration Excel would be in when a user would go through those steps, if you step away from that you are likely to wind up with instability cropping up in generic error codes as 5 and 1004.
In this case I believe you should do
wbb.Worksheets("b").Activate
before you start a copy from worksheet("b").
The real problem here is not that you didn't activate the sheet (though that does work, it's not a good solution)
wbb.Worksheets("b").Range(Cells(i, 1), Cells(i, 8)).Copy
Here the Cells() calls (unlike the Range() call) are not qualified by any worksheet object, so they will default to the ActiveSheet. In a regular module this is equivalent to writing:
wbb.Worksheets("b").Range(ActiveSheet.Cells(i, 1), ActiveSheet.Cells(i, 8)).Copy
...and is prone to failure when the active sheet is not what you expect.
This is robust and doesn't require you to activate a specific worksheet:
With wbb.Worksheets("b")
.Range(.Cells(i, 1), .Cells(i, 8)).Copy
End With

RANGE() working only in modules? (Excel VBA) [duplicate]

I'm trying to move some data from one workbook into another by assigning the values from one range to another. When I use the normal Range syntax to specify the destination range (Range("A1:B2")) my code works, but if I try to use the Range, Cells syntax (Range(Cells(1,1),Cells(2,2))) my code doesn't work.
I activate the destination workbook (ActiveWorkbook) and have the code running in the source workbook (ThisWorkbook).
This code works:
ActiveWorkbook.Worksheets(1).Range("A1:B2").Value _
= ThisWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value
But This code does not:
ActiveWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value _
= ThisWorkbook.Worksheets(1).Range(Cells(1, 1), Cells(2, 2)).Value
The error I get is Run-time error '1004': Applicaton-defined or object-defined error.
Does anyone know why using the cells object is causing me problems, or if there is some other problem I'm not aware of?
The problem is that Cells is unqualified, which means that the sheet to which those cells refer is different depending on where your code is. Any time you call Range or Cells or Rows or UsedRange or anything that returns a Range object, and you don't specify which sheet it's on, the sheet gets assigned according to:
In a sheet's class module: that sheet regardless of what's active
In any other module: the ActiveSheet
You qualify the Range reference, but the Cells reference is unqualified and is likely pointing to the Activesheet. It's like writing
ThisWorkbook.Worksheets(1).Range(ActiveSheet.Cells(1, 1), ActiveSheetCells(2, 2)).Value
which of course doesn't make any sense unless ThisWorkbook.Worksheets(1) happens to be active. I often like to use a With block so that I make sure everything is fully qualified.
With Sheets(1)
.Range(.Cells(1,1), .Cells(2,2)).Value = "something"
End With
But you refer to two different sheets, so you'll be better off using short sheet variables like:
Dim shSource As Worksheet
Dim shDest As Worksheet
Set shSource = ThisWorkbook.Worksheets(1)
Set shDest = Workbooks("myBook").Worksheets(1)
shDest.Range(shDest.Cells(1, 1), shDest.Cells(2, 2)).Value = _
shSource.Range(shSource.Cells(1, 1), shSource.Cells(2, 2)).Value
But really, if you're going to hardcode the Cells arguments, you could clean that up like
shDest.Cells(1, 1).Resize(2, 2).Value = shSource.Cells(1, 1).Resize(2, 2).Value

"Run-Time error '438': Object doesn't support this property or method." Range.values = Range.values

I am trying to copy a range of data from a Excel workbook to another workbook without the need of selecting any workbook during this process and using worksheet object names.
I want to do this because the selection process:
Windows("SourceWorksheet").Activate - Sheet("SourceSheet").Select -
Range("SourceRange").Copy - Windows("DestinationWorksheet").Activate
- Sheet("DestinationSheet").Select - Range("DestinationRange").Paste
is very slow compare with
DestinationWorkBook.DestinationSheet.Range("DestinationRange").Value =
SourceWorkBook.SourceWorkSheet.Range("SourceRange").Value
I have got this working using sheets tap names and letter ranges:
Workbooks(DestinationWorkBook).Sheets("DestinationSheet").Range("A:C").Value = _
Workbooks(SoureceWorkBook).Sheets("SourceSheet").Range("A:C").Value
And also using semi-dynamic ranges and sheets tap names:
lastRow = Cells(Workbooks(Limits_Name).Sheets("SourceSheet").Rows.Count, _
"A").End(xlUp).Row
Workbooks(DestinationWorkBook).Sheets("DestinationSheet").Range("A1:C" & lastRow).Value = _
Workbooks(SourceWorkBook).Sheets("SourceSheet").Range("A1:C" & lastRow).Value
My problems starts when I use sheets object names instead of sheets names or cells instead of ranges. In those situation is when I get that error:
Workbooks(DestinationWorkBook).shtDestinationSheet.Range("A:C").Value = _
Workbooks(SourceWorkBook).Sheets("SourceSheet").Range("A:C").Value
OR
lastRow = Cells(Workbooks(SourceWorkBook).Sheets("SourceSheet").Rows.Count, "A").End(xlUp).Row
lastCol = Cells(1, Workbooks(SourceWorkBook).Sheets("SourceSheet").Columns.Count).End(xlToLeft).Column
Workbooks(DestinationWorkBook).Sheets("DestinationSheet").Range(Cells(1, 1), Cells(lastRow, lastCol)).Value = _
Workbooks(SourceWorkBook).Sheets("SourceSheet").Range(Cells(1, 1), Cells(lastRow, lastCol)).Value
OR (this is the ideal code)
lastRow = Cells(Workbooks(SourceWorkBook).Sheets("SourceSheet").Rows.Count, "A").End(xlUp).Row
lastCol = Cells(1, Workbooks(SourceWorkBook).Sheets("SourceSheet").Columns.Count).End(xlToLeft).Column
Workbooks(DestinationWorkBook).shtDestinationSheet.Range(Cells(1, 1), Cells(lastRow, lastCol)).Value = _
Workbooks(SourceWorkBook).Sheets("SourceSheet").Range(Cells(1, 1), Cells(lastRow, lastCol)).Value
I would like to know what is the difference between using Sheets("sheetname") and the and the sheet object name which can be given under the (name) property of the worksheet object properties.
If I use Sheets("SourceSheet").Range("") I do not need to select the sheet but using sthSourceSheet.Range("") I do.
I like to use sheet object names because the VBA code still works if the sheet name is modified.
First problem (solved):
When using an object for a Worksheet this includes also the Workbook.
While the Worksheet-Object is not a child of the workbook itself inside of the syntax like Workbook.Worksheet_Object. So either use Workbook.Worksheet(Worksheet_Object.Name) or just Worksheet_Object
Second probem (solved):
There is a problem using Range(Cells(), Cells()) in a non-active workbook... Using only Cells() with no parent sometimes causes trouble cus VBA want's to use a full path. Just Cells will retun a [workbook]Sheet!Range while using with a different parent this causes an error. VBA will get a return like: Wb1.Ws1.Range(Wb2.Ws2.Range).
You can try something like:
htDestinationSheet.Range(htDestinationSheet.Cells(1, 1), htDestinationSheet.Cells(lastRow, lastCol)).Value = Workbooks(SourceWorkBook).Sheets("SourceSheet").Range(Workbooks(SourceWorkBook).Sheets("SourceSheet").Cells(1, 1), Workbooks(SourceWorkBook).Sheets("SourceSheet").Cells(lastRow, lastCol)).Value
which should work... However: i think it's better to stay with str (looks better)

Setting a range on a different sheet without having to select that sheet

I'm simply trying to set a Range object to gather data scattered across different columns on one sheet ("Backtest") into one compact set of data (each column one next to another) on a second sheet ("chartData"), so as to easily display those on a chart at later stage.
My understanding is that using the With... End With should allow to specify in which sheet the range is to be retrieved by the Set statement. Yet if that sheet is not selected beforehand (as shown on the third line), i run into an
error 1004 "Application-defined or object-defined error"
.
Sub prepareData()
Set wsChartData = Worksheets.Add
wsChartData.Name = "chartData"
wsBacktest.Select
With wsBacktest
Set myRangeTimestamp = .Range(Cells(17, 1), Cells(lastRow, 1))
Set myRangeData = .Range(Cells(17, [colMtM]), Cells(lastRow, [colPnL]))
End With
wsChartData.Range("A1").Value = "Timestamp"
wsChartData.Range("B1").Value = "MtM"
wsChartData.Range("C1").Value = "PnL"
myRangeTimestamp.Copy Destination:=wsChartData.Range("A2")
myRangeData.Copy Destination:=wsChartData.Range("B2")
wsChartData.Range("A2").EntireColumn.AutoFit
End Sub
This is not a blocking point as such, but, well, you know... aesthetics...
This:
With wsBacktest
Set myRangeTimestamp = .Range(Cells(17, 1), Cells(lastRow, 1))
Set myRangeData = .Range(Cells(17, [colMtM]), Cells(lastRow, [colPnL]))
End With
Is simply equivalent to this:
Set myRangeTimestamp = wsBacktest.Range(Cells(17, 1), Cells(lastRow, 1))
Set myRangeData = wsBacktest.Range(Cells(17, [colMtM]), Cells(lastRow, [colPnL]))
Now, Cells is implicitly referring to the active sheet, as #Doug mentioned, so you should also explicitly qualify them:
Set myRangeTimestamp = wsBacktest.Range(wsBacktest.Cells(17, 1), wsBacktest.Cells(lastRow, 1))
Set myRangeData = wsBacktest.Range(wsBacktest.Cells(17, [colMtM]), wsBacktest.Cells(lastRow, [colPnL]))
The With block simply makes fewer repetitions of wsBacktest; with or without it, an unqualified Cells is an implicit reference to the active sheet, which you should avoid at least as much as Select.
So the error is occurring because you intend to get a range on the wsBacktest sheet, but unless you first activate that sheet, you're using cells from another sheet to get that. Boom.
wsBacktest is neither declared, defined nor set. Excel does not know what you're talking about. Declare it and it will work. See this example.
Sub test()
Dim ws As Worksheet
Dim rng1 As Range, rng2 As Range
Set ws = ThisWorkbook.Worksheets("Sheet1")
With ws
Set rng1 = .Range("A1")
Set rng2 = .Range("B1")
End With
MsgBox rng1 & " " & rng2
End Sub