RANGE() working only in modules? (Excel VBA) [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

Avoiding select while referring to column by number [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

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

"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)

Can't work with ranges if workbook and sheet are not active [duplicate]

This question already has answers here:
Excel VBA, getting range from an inactive sheet
(3 answers)
Closed 2 years ago.
I am getting an Application or Object Defined Error when I try to import values from one workbook to another. I have been able to resolve it by explicitly activating the workbooks and selecting the sheets before referencing the range on each, but I would like to avoid that if possible. Both workbooks are open at this point in the code. Any thoughts?
This generates errors for me:
Dim wbImport As Workbook
Dim wbReceive As Workbook
Const sExcept = "Sheet2 Name"
Const sSht = "Sheet1 Name"
Dim rExceptions As Range
wbReceive.Sheets(sExcept).Rows(1).Insert shift:=xlDown
Set rExceptions = wbImport.Sheets(sSht).Range(Cells(rCell.Row, iHeadCol), Cells(rCell.Row, iLastCol))
wbReceive.Sheets(sExcept).Range(Cells(1, iHeadCol), Cells(1, iLastCol)).Value = rExceptions.Value 'error occurs here
This runs fine, but I'd like to avoid the .Select and .Activate
wbReceive.Sheets(sExcept).Rows(1).Insert shift:=xlDown
wbImport.Activate
wbImport.Sheets(sSht).Select
Set rExceptions = wbImport.Sheets(sSht).Range(Cells(rCell.Row, iHeadCol), Cells(rCell.Row, iLastCol))
wbReceive.Activate
wbReceive.Sheets(sExcept).Select
wbReceive.Sheets(sExcept).Range(Cells(1, iHeadCol), Cells(1, iLastCol)).Value = rExceptions.Value
As I was debugging, it looked like cells referenced in the wbReceive.Sheets(sExcept) line were actually referencing a different sheet in the wbReceive workbook. Not sure why that would be the case though, since the wb and sheet were explicitly referenced?
Set rExceptions = wbImport.Sheets(sSht).Range(Cells(rCell.Row, iHeadCol), _
Cells(rCell.Row, iLastCol))
You've qualified Range, but not Cells: either of these if not qualified with a specific sheet will refer to the ActiveSheet. Somewhat counter-intuitively, the (qualified) wrapping Range doesn't "casade" down...
Try this:
With wbImport.Sheets(sSht)
Set rExceptions = .Range(.Cells(rCell.Row, iHeadCol), _
.Cells(rCell.Row, iLastCol))
End with
The Cells reference within the range might be the hangup. I've gotten weird errors when using Range() with two cells in it. With just:
Range(Cells(1, iHeadCol), Cells(1, iLastCol))
It may be looking at ActiveSheet.Cells and if you try combining cells in different worksheets (or with an explicit reference on the range) you get errors. Try explicitly referencing the cells with:
Range(wbReceive.Sheets(sExcept)Cells(1, iHeadCol), wbReceive.Sheets(sExcept)Cells(1, iLastCol))
It looks ugly but you can probably clean it up with some worksheet objects.