Excel - Loop through table out of bounds error - excel

my code is to run through a table and store the cell color of column D while also storing the value of in column C as another variable. These variables are used to find a shape on another the "main" tab and update that color to the color that was stored in CellColor. When I added the loop part of the code I get an out of bounds error (-2147024809 (80070057)).
Sub Update()
Dim CellColor As Long
Dim ShapeColor As Variant
Dim rng As Range, Cell As Range
Dim i As Integer
Worksheets("Sheet1").Select
Set rng = Range("C2:C100")
For i = 2 To rng.Rows.Count
CellColor = rng.Cells(RowIndex:=i, ColumnIndex:="D").DisplayFormat.Interior.Color
ShapeColor = rng.Cells(RowIndex:=i, ColumnIndex:="C").Value
Worksheets("main").Shapes(ShapeColor).Fill.ForeColor.RGB = CellColor
i = i + 1
Next
Worksheets("main").Select
End Sub

Perhaps use a For Each loop here and Offset:
Set rng = Worksheets("Sheet1").Range("C2:C100")
Dim cell As Range
For Each cell In rng
ShapeColor = cell.Value
CellColor = cell.Offset(,1).DisplayFormat.Interior.Color
Worksheets("main").Shapes(ShapeColor).Fill.ForeColor.RGB = CellColor
Next
A brief explanation of your problem:
rng.Cells(RowIndex:=i, ColumnIndex:="C")
rng.Cells(RowIndex:=i, ColumnIndex:="D")
are not the cells you think they are, because they are offsetting but starting from column C. They are actually referring to columns E and F.
As an example: ? Range("C2").Cells(1, "C").Address returns $E$2, not $C$2.
Other points:
Remove the i = i + 1. Next is what increments i.
Avoid using Select: Set rng = Worksheets("Sheet1").Range("C2:C100").

Related

Loop to look for the closest value in a specific range

I have to run the code twice to get the right answer.
The bug is somewhere in the for loop commented as "finds static.press cell location"
Sub find()
Dim A As Double
Dim B As Variant
Dim c As Integer
Dim x As Range
Dim cell As Range
Dim rng As Variant
Dim r As Variant
Dim Mx As Long
Dim i As Long
Dim target As Double
Set wks = Worksheets("comefri")
Set wkks = Worksheets("TEST")
Dim p As Long
'RPM INPUT
A = wkks.Range("C18").value
'Static Pressure Input
B = wkks.Range("C19").value
'copy comefri values to test sheet
Sheets("comefri").Range("A9:gs24").Copy Destination:=Sheets("test").Range("a1:gs16")
With test
' Row Numb used in rangelookup
c = Range("C20").value
d = Range(Cells(c, 102), Cells(c, 201))
For Each cell In [a2:gs16]
cell = WorksheetFunction.Round(cell, 1)
Next cell
'Finds RPM cell location
Set cell = Range("a:a").find(What:=A, LookAt:=xlWhole, MatchCase:=fasle, SearchFormat:=False)
Range("c20") = cell.row
'finds static.press cell location
target = B
Set rng = Range(Cells(c, 102), Cells(c, 201))
'rng.Offset(, 1).ClearContents
Mx = Application.Max(rng)
For Each B In rng
If Abs(target - B) < Mx Then
Mx = Abs(target - B)
i = B.row
p = B.Column
End If
Next B
Debug.Print i
Debug.Print p
Range("d19").value = p
Range("e19").value = i
End With
End Sub
The first time the code runs, I think it uses the values from previous inputs and the second time I run it, it uses the new inputs.
I think I need a line of code to clear old inputs.
The problem is that you pull the value of c from a cell value (Sheets("TEST").Range("C20")). You update the cell value (on this line: Range("c20") = cell.row), but don't update the value of c. As such, when you set your rng variable, it's still using the old c value.
To resolve this, instead of this:
Set rng = Range(Cells(c, 102), Cells(c, 201))
Use this:
Set rng = wkks.Range(wkks.Cells(cell.Row, 102), wkks.Cells(cell.Row,201))
Lastly some generic advice:
As Cyril already stated, use descriptive variable names instead of single letters
Once a variable is set in the code, use the variable instead of referencing worksheet cells
Use proper indenting for your code to make it easier to read and follow
Always fully qualify your range objects to avoid confusion
Use your worksheet objects that you set instead of referencing worksheets by their codename

Copying Cell Value On The Same Row Based On Another Column Cell Color

I am trying to be able to search through a list in Column W and any cell in Column W that is highlighted Yellow to Copy Cell from Column B from the same row as colored cell in Column W.
This is what I have so far:
Sub CopyData()
Dim YellowField As Range
Dim YellowCell As Range
Dim Amortized As Worksheet
Dim Rollforward As Worksheet
Set Amortized = Worksheets("AMORTIZED")
Set Rollforward = Worksheets("Rollforward")
Set YellowField = Amortized.Range("W4", Amortized.Range("W4").End(xlDown))
For i = 4 To YellowField.UsedRange.Rows.Count
For Each YellowCell In YellowField
If YellowCell.Interior.Color = vbYellow Then
x = Amortized.Cells(i, ColumnD).Value
x.Copy Destination:= _
Rollforward.Range("B30").Offset(Rollforward.Rows.Count - 1, 0).End(xlUp).Offset(1, 0)
Exit For
End If
Next YellowCell
Exit For
Next i
End Sub
Currently when I run I get Error 439 on this line.
x = Amortized.Cells(i, ColumnD).Value
I was using .color and switched to .value because I feel it would assume if column D was colored I could be wrong though. Plus I feel I am still missing the loop here where the list would continue to be scanned for more colored cells in Column W
ColumnD is being read as a Variant it does not mean Column D Use 4 instead.
The inner loop is not needed and will give you a lot of false positive copies.
And to copy X you need to make it a Range and Set it. But in this case just use the cell itself.
Sub CopyData()
Dim LstRow As Long
Dim Amortized As Worksheet
Dim Rollforward As Worksheet
Set Amortized = Worksheets("AMORTIZED")
Set Rollforward = Worksheets("Rollforward")
LstRow = Amortized.Cells(Amortized.Rows.Count,23).End(xlUp).Row
For i = 4 To lstrow
If Amortized.Cells(i,23).Interior.Color = vbYellow Then
Amortized.Cells(i, 4).Copy Destination:= _
Rollforward.Cells(Rollforward.Rows.Count,2).End(xlUp).Offset(1,0)
End If
Next i
End Sub

For each loop in VBA Excel

I am a beginner in VBA trying to loop through cells from a specified range that is entered into a refEdit on a user form, this range always has 2 columns but could have any number of rows. The first column is a category and the second column is numerical values. I want to find the sum of the corresponding values of a specific category. For example, very time I come across the word "coffee" in a cell I want to take the value in the cell to its right and start summing them to print the value of all coffee in cell C1. How can I get this to work?
Here is what I have been working with:
dim cell, myRange as Range
dim c as string
dim r as long
Set myRange = Range(RefEdit1.Text)
c = "coffee"
r = 0
For Each cell In myRange
If VBA.LCase(cell) = VBA.LCase(c) Then
r = r + ActiveCell.Offset(0, 1).Value
End If
next cell
range("C1") = r
SumIf vs Loop
Loops are usually best avoided due to slowing down the code.
SumIf 'is' not case-sensitive so you are also avoiding the 'LCase-business'.
When declaring variables in one line, you have to 'use an As' for each variable or it will be declared as Variant (cell).
Option Explicit
Sub testSumIf()
Dim myRange As Range
Dim c As String
Set myRange = Range(RefEdit1.Text)
c = "coffee"
Range("C1").Value _
= Application.SumIf(myRange.Columns(1), c, myRange.Columns(2))
End Sub
Sub testLoop()
Dim cell As Range, myRange As Range
Dim c As String
Dim r As Long
Set myRange = Range(RefEdit1.Text)
c = VBA.LCase("coffee")
For Each cell In myRange.Cells
If VBA.LCase(cell.Value) = c Then
r = r + cell.Offset(0, 1).Value
End If
Next cell
Range("C1").Value = r
End Sub

Stack different columns into one column on a different worksheet

I want to copy all filled cells starting from C5 to column F of a different worksheet.
I referred to another post: Excel - Combine multiple columns into one column
Modified the code based on my needs.
Sub CombineColumns()
Dim Range1 As Range, iCol As Long, Range2 As Range, Check As Range, wks As Worksheets
Set Range1 = wks("T(M)").Range(Cells(5, 3), Cells(Cells(5, 3).End(xlDown).Row, Cells(5, 3).End(xlToRight).Column))
Set Check = wks("csv").Range("F1")
If IsEmpty(Check.Value) = True Then
Set Range2 = Check
Else
LastRow = wks("csv").Range("F" & Rows.Count).End(xlUp).Row
Set Range2 = wks("csv").Cells(LastRow, 6).Offset(1, 0)
End If
For iCol = 3 To Range1.Columns.Count
wks("T(M)").Range(Cells(5, iCol), Cells(Range1.Columns(iCol).Rows.Count, iCol)).Copy
wks("csv").Range2.PasteSpecial Paste:=xlPasteValuesAndNumberFormats
Next iCol
End Sub
But I kept getting the error message
"object doesn't support this method or property"
at the step of pasting. After I tried to qualify all the ranges, It says I didn't set the object variable.
Thank you so much for the help!
How about this?
Sub Transposes()
' Example just for hardcoded data
Dim inputRange As Range
Set inputRange = Sheets("Sheet1").Range("C5:F10").SpecialCells(xlCellTypeConstants)
Dim outputCell As Range
Set outputCell = Sheets("Sheet2").Range("A1")
Dim cell As Range
For Each cell In inputRange
Dim offset As Long
outputCell.offset(offset).Value = cell.Value
offset = offset + 1
Next cell
End Sub
Set the last row in ColumnF to be whatever you want, and if that changes dynamically, just use any one of the multiple techniques out there to find the last cell you need to copy/paste.

Detect non empty last cell location using Excel VBA

In my Excel sheet, I have VBA code to detect the last non-empty cell in Column A and add incremental serial number value in that cell (in below example cell A6 value should be SN104).
This processing is limited only to Column A, and in this image example first non-empty last cell is at A6, sometimes it can be after 100 cells or 1000 cells.
Is there any simple way to handle this scenario?
Public Function GetLastCell(ByVal startRng as Range) as Range
With startRng
Set GetLastCell = IIf(.Offset(1).Value = "", .Offset(0), .End(xlDown))
End With
End Function
For your example, you can define a Range variable rng, and call the above function in this way:
Dim rng as Range
Set rng = GetLastCell( Range("A1") )
Then rng is referring to the last cell of Column A
Something like
Dim lngLastUsedRow as Integer
lngLastUsedRow = Range("A65536").End(xlUp).Row
Dim lngFirstEmptyRow as Integer
lngFirstEmptyRow = Range("A65536").End(xlUp).Offset(1,0)
// do your increment
newValue = Cint(Mid(CurrentWorkSheet.Range("A" + lngLastUsedRow).Value,2)) + 1
CurrentWorkSheet.Range("A" & lngFirstEmptyRow).Value = "SN" + newValue
I don't have excel on me, I can't test it right now. But this should get you started.
Something like this which
Find the true last used cell in any Excel version, and handles a blank result
Parses the string in the last non-blank cell (handling any length of alpha then numeric)to update the next blank cell
Sub GetTrueLastCell()
Dim rng1 As Range
Dim objRegex As Object
Dim strFirst As String
Set rng1 = Columns("A").Find("*", [a1], xlFormulas)
If Not rng1 Is Nothing Then
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Pattern = "^(.+?[^\d])(\d+)$"
If .test(rng1.Value) Then
strFirst = .Replace(rng1.Value, "$1")
rng1.Value = strFirst & (Val(Right$(rng1.Value, Len(rng1.Value) - Len(strFirst)) + 1))
End If
End With
Else
MsgBox "Data range is blank"
End If
End Sub
Assumptions:
Next cell in list is empty
Serial N's only have three digits after 'SN' string (i.e., if it reaches 1000, earlier ones don't need padding, like '0100'
-
Dim rAll As Range, rLast As Range, rNext As Range, iNextSN As Integer
Set rAll = Intersect(Sheet1.Cells(1).CurrentRegion, Sheet1.Columns(1)) ' Column 'A' can be contiguous with others
Set rLast = rAll.Cells(rAll.Cells.Count) ' Last cell in current list
Set rNext = rLast.Offset(1) ' Next cell below current list
iNextSN = CInt(Right(rLast.Value, 3)) ' Get value of last serial N
rNext.Value = "SN" & iNextSN + 1 ' Assemble next SN with increment
-

Resources