generating a range from other cells excel vba - vba

I am not sure if this can be done to start with.
i am iterating through some cells and at some point I want to define a range like this:
Set rngtmp = Range(f.Column & c.Row & ":" & g.Column & c.Row)
f and g are pointing to single cells and they are okay (I mean that they work just fine) because I am also doing some operations taking them as a reference and they work.
c is the cell that i am currently at ( since I am iterating through all the cells). The range is always empty and I don't understand why.
f.column is smaller than g.column

You can use the .Cells() property.
Dim wb As Workbook, ws As Worksheet
Dim rngTmp As Range
Set wb = ThisWorkbook
Set ws = wb.Sheets(1)
With ws
Set rngTmp = .Range(.Cells(c.Row, f.Column), .Cells(c.Row, g.Column))
End With
You cannot use integers to determine the size of a range object; you are required to use the .Cells property to be able to use integers to build a range.
Edit:
As #Scott Holtzman mentioned, you must firstly pass .Row and then .Column into .Cells (the opposite to how you have it shown in your question).
As #eirikdaude mentioned, you can use .Range and then use the .Resize property; this allows you to use integers with the range, instead of having to use the .Cells property. This is an approach which I typically use when writing arrays to a worksheet.

Use Cells to refer to a single cell. You can then join these in a range:
Sub Test()
Dim rngtmp As Range
Dim f As Range
Dim c As Range
Dim g As Range
With ThisWorkbook.Worksheets("Sheet1")
Set f = .Range("A1")
Set c = .Range("D8")
Set g = .Range("L22")
Set rngtmp = .Range(.Cells(c.Row, f.Column), .Cells(g.Column, c.Row))
End With
End Sub
Note that .Range and .Cells will refer to Sheet1 due to the With...End With block.
https://msdn.microsoft.com/en-us/library/wc500chb.aspx

You can't use .Column as it returns the integer index of the column, not a letter.
Try something along the lines of
set rngtmp = Range(Cells(f.Row, c.Column), Cells(g.Row, c.Column))
of course you will need to reference sheets and cells and such as required

Related

Fill Empty Blank Cells with value within a region horizontaly defined

I'm trying to fill blank cells in a certain region with 0. The reagion should be defined in the current workbook but in sheet2 (not the current sheet). Also the place where it is supposed to fill is between columns
BU:CQ in the current region (not all 100 000 000 lines). Just the number of lines that define the table between columns BU and CQ. I know the problem lies in defining the region... See the code below.
What is missing?
Sub FillEmptyBlankCellWithValue()
Dim cell As Range
Dim InputValue As String
On Error Resume Next
InputValue = "0"
For Each cell In ThisWorkbook.Sheets("Sheet2").Range(BU).CurrentRegion
'.Cells(Rows.Count, 2).End(xlUp).Row
If IsEmpty(cell) Then
cell.Value = InputValue
End If
Next
End Sub
I've this code that i'm positive that works! But i don't wnat selection! I want somthing that specifies the sheet and a fixed range.
Now my idea is to replace "selection" with the desired range. - In this case in particular the range should be 1 - between BU:CQ; 2 - starting at row 2; 3 - working the way down until last row (not empty = end of the table that goes from column A to DE)
Sub FillEmptyBlankCellWithValue()
Dim cell As Range
Dim InputValue As String
On Error Resume Next
For Each cell In Selection
If IsEmpty(cell) Then
cell.Value = "0"
End If
Next
End Sub'
PS: And I also need to specify the sheet, since the button that will execute the code will be in the same workbook but not in the same sheet.
Use SpecialsCells:
On Error Resume Next 'for the case the range would be all filled
With ws
Intersect(.UsedRange, .Range("BU:CQ")).SpecialCells(xlCellTypeBlanks).Value = 0
End With
On Error GoTo 0
MUCH faster than looping !
Try using cells() references, such as:
For i = cells(1,"BU").Column to cells(1,"CQ").Column
cells(1,i).value = "Moo"
Next i
In your current code you list Range(BU) which is not appropriate syntax. Note that Range() can be used for named ranges, e.g., Range("TheseCells"), but the actual cell references are written as Range("A1"), etc. For Cell(), you would use Cells(row,col).
Edit1
With if statement, with second loop:
Dim i as long, j as long, lr as long
lr = cells(rows.count,1).end(xlup).row
For i = 2 to lr 'assumes headers in row 1
For j = cells(1,"BU").Column to cells(1,"CQ").Column
If cells(i,j).value = "" then cells(i,j).value = "Moo"
Next j
Next i
First off, you should reference the worksheet you're working with using:
Set ws = Excel.Application.ThisWorkbook.Worksheets(MyWorksheetName)
Otherwise VBA is going to choose the worksheet for you, and it may or may not be the worksheet you want to work with.
And then use it to specify ranges on specific worksheets such as ws.Range or ws.Cells. This is a much better method for specifying which worksheet you're working on.
Now for your question:
I would reference the range using the following syntax:
Dim MyRange As Range
Set MyRange = ws.Range("BU:CQ")
I would iterate through the range like so:
Edit: I tested this and it works. Obviously you will want to change the range and worksheet reference; I assume you're competent enough to do this yourself. I didn't make a variable for my worksheet because another way to reference a worksheet is to use the worksheet's (Name) property in the property window, which you can set to whatever you want; this is a free, global variable.
Where I defined testWS in the properties window:
Public Sub test()
Dim MyRange As Range
Dim tblHeight As Long
Dim tblLength As Long
Dim offsetLen As Long
Dim i As Long
Dim j As Long
With testWS
'set this this to your "BU:CQ" range
Set MyRange = .Range("P:W")
'set this to "A:BU" to get the offset from A to BU
offsetLen = .Range("A:P").Columns.Count - 1
'set this to your "A" range
tblHeight = .Range("P" & .Rows.Count).End(xlUp).Row
tblLength = MyRange.Columns.Count
End With
'iterate through the number of rows
For i = 1 To tblHeight
'iterate through the number of columns
For j = 1 To tblLength
If IsEmpty(testWS.Cells(i, offsetLen + j).Value) Then
testWS.Cells(i, offsetLen + j).Value = 0
End If
Next
Next
End Sub
Before:
After (I stopped it early, so it didn't go through all the rows in the file):
If there's a better way to do this, then let me know.

VBA Object Required When Getting Row From Range

I am trying to extract a single row from a range object within a function. The range is declared as a variant, and then set to a range within my sheet. I want to be able to pick out a specific row, so I tried to call .Rows(indexfrom, indexto), but I get the error Object Required. I've tried setting compareRow instead of just declaring it, but that doesn't seem to change anything. I believe it's caused because callLogRange only exists as a reference to the range object. If this is the case, how can I use the reference to get the row from the range? Alternatively, am I just missing something that enables you to get the row?
Thank you.
Dim callLogRange As Variant
callLogRange = (Sheets("CallLog").Range("B2:L" & lastRow))
Dim compareRow As Variant
compareRow = callLogRange.Rows(thisRow, thisRow)
Dim them as Ranges and use Set:
Sub dural()
Dim callLogRange As Range, thisRow As Long, lastRow As Long
lastRow = 13
Set callLogRange = Sheets("CallLog").Range("B2:L" & lastRow)
thisRow = 5
Dim compareRow As Range
Set compareRow = callLogRange.Rows(thisRow)
MsgBox compareRow.Address(0, 0)
End Sub
EDIT#1:
the cells are in the sixth row of the worksheet which is the fifth row of the primary range
if you instantiate compareRow without the Set, you are actually creating an internal VBA array rather than a Range.
Drop the parentheses.
This:
callLogRange = (Sheets("CallLog").Range("B2:L" & lastRow))
Is evaluating Sheets("CallLog").Range("B2:L" & lastRow) as a value. Remove the parentheses and you'll be assigning a 2D array instead.
Or Set the reference and you'll be assigning a Range object reference, as in Gary's answer

Assigning two ranges from separate sheets to a variable

I have 3 worksheets and I am trying to assign a range to a variable on one of the sheets, based on ranges in two other different worksheets. Here is my code:
Sub Combine()
Dim range1 As Range
Dim range2 As Range
Dim ID As Range
Set range1 = Worksheets(3).Range("A2:A")
Set range2 = Worksheets(4).Range("A2:A")
Set newRng = Worksheets(6).Range(range1, range2)
End Sub
I'm getting back a
Run-time error '1004'
Any suggestions?
A range can't span multiple worksheets.
This may work, depending on what you ultimately need to do:
Set newRng = Worksheets(6).Range(range1.Address, range1.Address)
But, since these ranges have the same address in your example, I think what you want is not a Range object combining them, but some other data structure, like an array, collection, or dictionary.
NOTE Your ranges are not valid to begin with, Range("A2:A") is not valid, so you'll need to fix that. See here for reliable ways to find the "last" cell in a range. I've modified it to bring in the entire column A (except A1) but you will probably want to fine-tune that.
newRange will have to be a different data type for this to work without raising a Mismatch error, for example a Collection:
Sub Combine()
Dim coll as New Collection
Dim range1 As Range
Dim range2 As Range
Dim ID As Range
coll.Add Worksheets(3).Range("A2:A" & Rows.Count)
coll.Add Worksheets(4).Range("A2:A" & Rows.Count)
Set newRng = coll
End Sub
Or as an array of range:
Sub combine()
Dim newRange(1) As Range
Set r1 = Worksheets(3).Range("A2:A" & Rows.Count)
Set r2 = Worksheets(4).Range("A2:A" & Rows.Count)
Set newRange(0) = r1
Set newRange(1) = r2
End Sub
Using the array example above, you can then assign the values to another location, modify as needed:
Worksheets(4).Range("B1").Value = newRange(0).Value
Worksheets(4).Range("B2").Value = newRange(1).Value

excel vba set one range object by other two range object

Here is my problem. I have two Range Object. For example,
Set rg3 = Range("B2")
Set rg4 = Range("B3000")
I want to do this
Range("rg3:rg4").PasteSpecial (xlPasteAll)
But it show error. How can I select the region by two range object.
Range("B2:B3000") is not correct in my case because those two range would always updated by offset function.
Thanks for your help!!!
When you enter Range( the intellisense will show Range(Cell1, Cell2) as Range indicating the the Range object is expecting two cells.
So, seeing as rg3 and rg4 are two cells you can use Range(rg3, rg4).
You're using xlPasteAll so you could just use RangeBeingCopiedReference.Copy Destination:=Range(rg3,rg4)
Edit - and as #Robin says, what do you mean by the offsetting?
Edit 2:
If you want to loop through a range then using Cells is easier as it accepts a column number rather than a column letter.
This example will copy columns A:J over to U:AD one column at a time.
Sub Test()
Dim rg3 As Range, rg4 As Range
Dim x As Long
With ThisWorkbook.Worksheets("Sheet1")
For x = 1 To 10
.Range(.Cells(2, x), .Cells(3000, x)).Copy _
Destination:=.Range(.Cells(2, x + 20), .Cells(3000, x + 20))
Next x
End With
End Sub
Also - look up reference on WITH... END WITH - https://msdn.microsoft.com/en-us/library/wc500chb.aspx
I'd like to better understand your needs for better help
as a start, since your using of .PasteSpecial xlPasteAll I'd believe you're setting a source range outside a loop and paste it multiple times inside this latter shifting pasting range
you also explained "rg3 and rg4 is inside a for loop, each time it will move to next colmn by offset(0, 1)"
so this would initially lead to:
Option Explicit
Sub main()
Dim copyRng As Range, rg3 As Range, rg4 As Range
Dim i As Long
Set rg3 = Range("B2") '<~~ your rg3 range setting
Set rg4 = Range("B3000") '<~~ your rg4 range setting
Set copyRng = ... '<~~ your setting of the "source" range to be copied once and pasted many
copyRng.Copy '<~~ copy "source" Range once ...
With Range(rg3, rg4) '<~~ ... set your initial "target" range ...
For i = 1 To 10
.Offset(, i).PasteSpecial xlPasteAll '<~~ ... and paste "source" range offseting "target" once
Next i
End With
End Sub
but this would also be uselessly long and slow, since you could simply write:
Option Explicit
Sub main()
Dim copyRng As Range, rg3 As Range
Set rg3 = Range("B2") '<~~ just set the "beginning" of the target range
Set copyRng = ... '<~~ your setting of the "source" range to be copied once and pasted many
copyRng.Copy copyRng.Copy Destination:=rg3.Resize(, 10)
End Sub
so what's your real need?

Remove Duplicates from range without deleting data

So I essentially want to take a range from one worksheet and remove the duplicates, save that range, without duplicates, as a some object in my vba code. Then paste that range into another sheet. However, I do not want to touch any of the data in Sheet1 when removing the duplicates.
So I have something like:
Sub removeduplicates()
Dim rng As Range
Dim num As Long
With Worksheets("Sheet1")
Set rng = .Range("A2").End(xldown).RemoveDuplicates
num = rng.Row
End With
With Worksheets("Sheet4")
.UsedRange.ClearContents
.
.
.
'Need some code here to essentially paste (w/transpose) in Sheet4 Row 1 columns A to
'to Row 1 column 'num' value. So similar to:
.Range(.Cells(1,1), .Cells(1,num))
Hopefully you understand what I am going for. I probably need to use an array or something instead but I'm just stuck. And this code has probably many mistakes. Its just after a lot of playing around.
Thanks.
copy column A from Sheet1 to Sheet4
remove duplicates from Sheet4 column A
in Sheet4 copy column A to row #1
.
Sub removeduplicates()
Dim rng As Range
Dim s1 As Worksheet, s4 As Worksheet
Set s1 = Sheets("Sheet1")
Set s4 = Sheets("Sheet4")
Dim num As Long
s4.Cells.ClearContents
num = s1.Cells(Rows.Count, 1).End(xlUp).Row
s1.Range("A2:A" & num).Copy s4.Range("A2")
s4.Range("A:A").removeduplicates Columns:=1
num = s4.Cells(Rows.Count, 1).End(xlUp).Row
s4.Range("A1:A" & num).Copy
s4.Range("B1").PasteSpecial Transpose:=True
End Sub
I think Jean-Claude has a good suggestion: copy the entire range, and then do the .RemoveDuplicates on the destination worksheet.
If you must do it in memory, it is possible without even using the .RemoveDuplicates method:
Sub removeduplicates()
Dim r as Range
Dim dictValues as Object
Set dictValues = CreateObject("Scripting.Dictionary")
For each r in Worksheets("Sheet1").Range("A2").End(xldown).Cells
dictValues(r.Value) = r.Value
Next
With dictValues
Worksheets("Sheet4").Range("A1").Resize(1, .Count).Value = .Keys()
End With
NOTE in the event that there are mope than 16,384 unique values in the rng (for Excel 2007+) this will fail.