looping through a range of cells - vba

I need to run the function AddColumnofData on each cell from c27 and every contiguous non empty cell to the right, but I get a "Run-time error 424 object required", any help woul dbe greatly appreciated.
Set col = Range("$C$27", Range("$C$27").End(xlToRight))
For Each c In col
AddColumnofData (c)
Next c

On the assumption you have defined AddColumnofData as
Sub AddColumnofData(c As Range)
...
End Sub
your call to it needs to be
AddColumnofData c
(that is, remove the brackets)
Jesse's advice to DIM your variables, while not not manditory is good advice. Applies to col as well. To make it manditory add Option Explicit to the top of your module.

You can declare or set your range objects before passing them to your function. To prove that you are passing the correct values to your function, try this.
Dim r As Range '-- if you don't declare it as a range type you get a variant type as default
Dim c As Range '-- this is used to store the single cell in the For Each loop
Set r = Range("A1:D1") '-- substitute your range as per your example
For Each c In r '-- you could also use r.cells
MsgBox c.Value '-- pass to your function instead of a call to the Message Box
Next
This produces a series of 4 Message Boxes containing the values in cells A1 to D1 of the active worksheet, if your Range "r" is seriously large then pass it to Debug.Print instead.

If you declare c:
Dim c as Range
Then what you have should work.

Related

Excel VBA Make Cell Active in a Specified Range

I'm not sure why the following code gives a "Not found" Message when the value in the initial active cell (-15.0) is also a value within the specified range.
Sub Test()
Dim c As Double
Dim srchRng As Range
With ActiveWorkbook.ActiveSheet
c = ActiveCell.Select
Set srchRng = .Range("V17:V37").Find(what:=c)
If srchRng Is Nothing Then
MsgBox "Not found"
End If
End With
End Sub
Note sometimes a value of 0 exists within the specified range. If so I don't need to do anything but if 0 does not exist, I first need to find the least negative value (I use separately within the worksheet =MAX(IF(V17:V37<=0,V17:V37),MIN(V17:V37)) and this becomes my initial active cell value [eg -15.0] to look for in the specified range), and this least negative value will then be set to zero (by using a goal seek function in this cell)
So this macro will ultimately incorporate an If statement or conditional lookup
Any feedback appreciated.
I made suggested changes but revised code below still returns "Not found".
Cell V38 has the value -15.0 but this number does appear in the range V17:V37.
This simple macro should result in the cell in the range corresponding to the c value being selected. Any further help appreciated.
Dim c As Double
Dim srchRng As Range
With ThisWorkbook.Sheets("Reel_Pack")
c = Range("V38")
Set srchRng = .Range("V17:V37").Find(what:=c)
If srchRng Is Nothing Then
MsgBox "Not found"
End If
End With
End Sub
I found the following code to do the above.
Dim c As Double
c = ThisWorkbook.Sheets("Sheet1").Range("V58").Value
Dim cel As Range
For Each cel In ThisWorkbook.Sheets("Sheet1").Range("V17:V57")
With cel
If .Value = c Then
.Select
End If
End With
Next cel
End Sub
But can someone suggest please how to improve this by actually incorporating the equation I have in cell V58 within this macro? As mentioned that equation is =MAX(IF(V17:V37<=0,V17:V37),MIN(V17:V37)).
So the macro would look into the range V17:V37 and if there is an exact zero then Do Nothing otherwise locate the cell with the least negative number (which is what the equation above does) and select that cell.
I hope this is the correct reason:
c = ActiveCell.Select is returning the value -1 which equates to TRUE in VBA.
So, I think, the line is asking the question c = ActiveCell is Selected? which returns a boolean TRUE/FALSE converted to a double which equals -1.
c = ActiveCell returns the default property of the ActiveCell which is Value.
So that line should read c = ActiveCell or c = ActiveCell.Value rather than c = ActiveCell.Select.
Edit:
Not so sure of my reasoning now - c= Range("A1").Select selects cell A1 and returns -1 still.
I guess that why you should avoid Select like the plague unless you want to actually select a cell rather than just reference it. Have a read of How to avoid using Select in Excel VBA

Count values that aren't blank or N/A - VBA

I had figured out this formula to count all those values that weren't blank, but the system updated the template and now besides blank it has also "N/A" values.
How can I transform this
=COUNTIF('R Plan'!XT2:XT3658,"<>")
To test if besides NOT blank also test for NOT N/A
Because I tried this
=COUNTIF('R Plan'!XT2:XT3658,"<>" OR "<>N/A")
and I'm getting a message that we found an error on your formula
If you're using >=XL2007 then you can use COUNTIFS:
=COUNTIFS('R Plan'!XT2:XT3658,"<>",'R Plan'!XT2:XT3658,"<>N/A")
If you're using <=XL2003 then you can use:
=SUM(COUNTIF('R Plan'!XT2:XT3658,"<>"),-COUNTIF('R Plan'!XT2:XT3658,"N/A"))
Count the number that are not empty and minus those that have N/A.
or
=SUMPRODUCT(('R Plan'!XT2:XT3658<>"")*('R Plan'!XT2:XT3658<>"N/A"))
If you want to use VBA, then this will work for you,
Put this in a cell and choose your range =COUNTBLANKS(B1,A1:A21) , B1 being the value you want to count and the second range is the range you want to count how many times that value occurs.
Add a module and paste this function in it.
Function COUNTBLANKS(r As Range, rng As Range) As Long
Dim x
Dim c
x = rng
For Each c In x
If c = r Then
COUNTBLANKS = COUNTBLANKS + 1
End If
Next c
End Function

Referencing Cells within Named Range in VBA

I'd like to know if its possible to use Cells(r, c) within a named range in VBA.
Ex.: I have named range "Test" to be A1:B5 and I am working on a Macro that loops through this range, however I'd like to avoid explicit declarations of ranges as much as possible, so sheet manipulation can be as easier as possible.
In case what I said wasnt possible, I basically need to be able to loop/write through cells in the named ranges, if there is another approach for this I'd be more than glad to get a suggestion.
Thanks!
Sure, you can simply use e. g.
Worksheets("name").Range("Test").Cells(r, c)
and
Dim c As Range
For Each c In Worksheets("Name").Range("Test").Cells
Debug.Print c.Address
Next
I figured it out with a bit more of research
In case anyoone drops by wondering this:
Sub test()
dim r1 as Range
set r1 = Range("NamedRange")
f = r1.row
l = Range("NamedRange").Row + Range("NamedRange").Rows.Count - 1
Do while (Cells(f,1) <> "" and f <= l
'Run code
Loop
end sub

copy range values into variant using vba

I have the following code in a macro but when I run it, it only copies the value from cell B2 rather than the entire range of values from B2:D2 as I have specified in line 5 of the below code.
Sub copying()
Dim calval as variant
With worksheets("sheet1")
Set calval=.Cells(Rows.Count,"B").End(xlUp).Offset(2,3)
calval.value=Range("B2:D2").Value 'copy range of values
End With
End Sub
This is the data in cells B2:D2
21.7 21.3 22.4
Can someone please tell me how to get calval to be assigned the full range of values from B2:D2, rather than just the value in B2.
You have a few problems here. Firstly when copying to variants, they are not objects so you don't need to use set. They also don't have ranges as they variables. You also need to copy the value to a variant before you can set it to the output range so the order is a little off. The following code will work:
Sub Copying()
Dim calval as Variant
'Read it in from the worksheet
With Worksheets("Sheet1")
calval=.Range("B2:D2").value
'Set it back to the dsired range using the bounds of the variant instead of hardcoding.
.Range(.Cells(Rows.Count,"B").End(xlUp).Offset(2,3), .Cells(Rows.Count,"B").End(xlUp).Offset(1 + UBound(calval, 1), 2 + UBound(calval, 2))).Value = calval
End With
End Sub
I understand you have accepted an answer, here is another method to achieve what you need: Using WorkSheetFunction.Transpose method.
Dim calval as Variant
'--- Range("B2:D2").Value
calval = WorkSheetFunction.Transpose(Sheets(1).Range("B2:D2").Value)
You are free to use, offset, resize according to your needs.
e.g. expand your range up to B12
calval = WorkSheetFunction.Transpose(Sheets(1).Range("B2:D2").Resize(10).Value)

Get the current cell in Excel VB

I have a small script in Excel/VB that I'm trying to get working. All I want to do is select a dynamic range of data to copy but I can't seem to find any help/code on how to get the grid data (like A11).
Here is code I have from macro recording that selects the range of data:
Range("D291:D380").Select
I was hoping I could just do Range(Current).Select or something but that doesn't work.
How do I get the current cell using VBA?
Have you tried:
For one cell:
ActiveCell.Select
For multiple selected cells:
Selection.Range
For example:
Dim rng As Range
Set rng = Range(Selection.Address)
This may not help answer your question directly but is something I have found useful when trying to work with dynamic ranges that may help you out.
Suppose in your worksheet you have the numbers 100 to 108 in cells A1:C3:
A B C
1 100 101 102
2 103 104 105
3 106 107 108
Then to select all the cells you can use the CurrentRegion property:
Sub SelectRange()
Dim dynamicRange As Range
Set dynamicRange = Range("A1").CurrentRegion
End Sub
The advantage of this is that if you add new rows or columns to your block of numbers (e.g. 109, 110, 111) then the CurrentRegion will always reference the enlarged range (in this case A1:C4).
I have used CurrentRegion quite a bit in my VBA code and find it is most useful when working with dynmacially sized ranges. Also it avoids having to hard code ranges in your code.
As a final note, in my code you will see that I used A1 as the reference cell for CurrentRegion. It will also work no matter which cell you reference (try: replacing A1 with B2 for example). The reason is that CurrentRegion will select all contiguous cells based on the reference cell.
The keyword "Selection" is already a vba Range object so you can use it directly, and you don't have to select cells to copy, for example you can be on Sheet1 and issue these commands:
ThisWorkbook.worksheets("sheet2").Range("namedRange_or_address").Copy
ThisWorkbook.worksheets("sheet1").Range("namedRange_or_address").Paste
If it is a multiple selection you should use the Area object in a for loop:
Dim a as Range
For Each a in ActiveSheet.Selection.Areas
a.Copy
ThisWorkbook.worksheets("sheet2").Range("A1").Paste
Next
Regards
Thomas
If you're trying to grab a range with a dynamically generated string, then you just have to build the string like this:
Range(firstcol & firstrow & ":" & secondcol & secondrow).Select
I realize this doesn't directly apply from the title of the question, However some ways to deal with a variable range could be to select the range each time the code runs -- especially if you are interested in a user-selected range. If you are interested in that option, you can use the Application.InputBox (official documentation page here). One of the optional variables is 'type'. If the type is set equal to 8, the InputBox also has an excel-style range selection option. An example of how to use it in code would be:
Dim rng as Range
Set rng = Application.InputBox(Prompt:= "Please select a range", Type:=8)
Note:
If you assign the InputBox value to a none-range variable (without the Set keyword), instead of the ranges, the values from the ranges will be assigned, as in the code below (although selecting multiple ranges in this situation may require the values to be assigned to a variant):
Dim str as String
str = Application.InputBox(Prompt:= "Please select a range", Type:=8)
Try this
Dim app As Excel.Application = Nothing
Dim Active_Cell As Excel.Range = Nothing
Try
app = CType(Marshal.GetActiveObject("Excel.Application"), Excel.Application)
Active_Cell = app.ActiveCell
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
' .address will return the cell reference :)