jump to last non-empty cell in row - vba

Saved a Macro where I would go to to the last non-empty cell in a row by using CTRL+Right Arrow.
The macro, however, was saved by logging the J23 cell.
I want it to be dynamic so that if last non-empty cell changes, for instance, it is N23, it jumps there.
I would like that my other steps would then always link to cells L30, M30, N30 and O30 but in this case they are using relative coordinates (I tried to edit the macro from J23 to N23, for instance, and the linked cells change)
What are the code lines that I can use to make it dynamic the way I need?
Thank you for your help
Sub KPILinks()
'
' KPILinks Macro
'
'
Range("I22").Select
Selection.End(xlToRight).Select
Range("J23").Select
ActiveCell.FormulaR1C1 = "=R[7]C[2]"
Range("J24").Select
ActiveCell.FormulaR1C1 = "=R[6]C[3]"
Range("J25").Select
ActiveCell.FormulaR1C1 = "=R[5]C[4]"
Range("J26").Select
ActiveCell.FormulaR1C1 = "=R[4]C[5]"
Range("J27").Select
End Sub

borrowed from https://www.rondebruin.nl/win/s9/win005.htm
Sub LastRowInOneColumn()
'Find the last used row in a Column: column A in this example
Dim LastRow As Long
With ActiveSheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
MsgBox LastRow
End Sub

Related

First blank ("") cell in column with IF formula

I have a macro that exactly copies one sheet's data into another.
Sub QuickViewRegMgmt()
("Reg Management").Select
Cells.Select
Selection.Copy
Sheets("Quick View Reg Mgmt").Select
Cells.Select
ActiveSheet.Paste
End Sub
I would like for this macro to also go to the last non-blank cell in Column C (or first blank, I really don't care either way). I tried simple end/offset code, e.g.
Range("A1").End(xldown).Offset(1,0).Select
My problem, however, is that the direct copy macro also copies the underlying formulas, which for Column C is an IF formula. Therefore, no cell in the column is actually empty, but rather they all have an IF formula resulting in a true/false value (respectively, a "" or VLOOKUP).
=IF(VLOOKUP('Reg Management'!$Y260,'Reg Guidance'!$A:$V,3,FALSE)=0,"",VLOOKUP('Reg Management'!$Y260,'Reg Guidance'!$A:$V,3,FALSE))
That means the end/offset code goes to the last cell in the column with the formula (C1000) instead of going to the first cell that has a value of "" (which is currently C260).
What code can I add to this macro to select the first cell that contains an IF formula resulting in a value of "" ---- which has the appearance of being blank?
After trying to be fancy with SpecialCells(), or using Find() or something I couldn't get it ...so here's a rather "dirty" way to do it:
Sub test()
Dim lastRow As Long, lastFormulaRow As Long
lastRow = Range("A" & Rows.Count).End(xlUp).Row
Dim i As Long
For i = lastRow To 1 Step -1
If Cells(i, 1).Formula <> "" And Cells(i, 1).Value = "" Then
lastFormulaRow = i
Exit For
End If
Next i
End Sub
Edit2: Here's one using .SpecialCells(). Granted I think we can whittle this down more, I like it better:
Sub lastRow()
Dim tempLastRow As Long
tempLastRow = Range("C" & Rows.Count).End(xlUp).Row
Dim lastRow As Range
Set lastRow = Columns(3).SpecialCells(xlCellTypeFormulas).Find(What:="", LookIn:=xlValues, LookAt:=xlWhole, searchdirection:=xlPrevious, after:=Range("C" & tempLastRow))
Debug.Print lastRow.Row
End Sub
It returns 10 as the row.
Edit: Be sure to add the sheet references before Range() and Cells() to get the last row. Otherwise, it's going to look at your active sheet to get the info.

Excel macro - check for a string in a cell, run a routine, move to the next row, do it again

I am not a Dev, but given I do use Excel, I have been tasked to create a looping macro that will check for a string ('Resource') in a cell and if it finds that string, then run a Copy and Paste code and then move to the next row. This starts at row 5 and runs continuously until row 199, but does not work on every row, hence the validation for the string Resource.
I have managed to create the macro for the Copy and Paste but it also has issues as I created it using the macro recorder and it only works on the row I actually did the recording on.
I am at a complete loss, can anyone help?
this is what I have so far
A New Resource name is added manually to the spreadsheet
the user clicks cell (C6) to focus the curser
the user clicks a macro button called 'Forecast for Future Project 1' to start the macro
On the button click the Macro will:
Interogate if cell to the left of current cell (B6) = 'Resource'
IF Yes, THEN
Sub CP()
DO
Range("C6").Select
Selection.Copy
Application.Goto Reference:="ProjAdd"
ActiveSheet.Paste
Application.CutCopyMode = False
ActiveCell.FormulaR1C1 = _
"=SUMIF('Current Project Utilisation'!R2C1:R62C1,RC1,'Current Project Utilisation'!R2C:R62C)+SUMIF('Future Project 1'!R2C1:R62C1,RC1,'Future Project 1'!R2C:R62C)"
Range("ProjAdd").Select
Selection.Copy
Range("C6").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Selection.Copy
Range(Selection, Selection.End(xlToRight)).Select
ActiveSheet.Paste
Range("B6").Select
Loop Until ActiveCell.Address(0,0) = "$B$199"
End Sub
Move to cell under original active cell (C7) and Repeat the Macro until cell C199 is reached
If (B6) does not = 'Resource' then move to go to the cell under (C7) aand Repeat the Macro until cell C199 is reached
Refresh Worksheet to update data
Would something like this work for you?
Sub CopyPasteResource()
Dim CopyRange As Range
Dim Cell As Range
Set CopyRange = Workbooks("YourWorkBookName").Sheets("Sheet1").Range("C6:C199")
For Each Cell In CopyRange
If InStr(1, Cell.Offset(0, -1).Text, "Resource") Then
Cell.Copy
'paste where you wish
End If
Next Cell
End Sub
EDIT: Or do you want to loop through B6:B199 and then C6:199? I'm not entirely clear on the aim.
Ah the old macro recorder, generating 90% extra code since 1997. I couldn't exactly figure out from your question what exactly is being copied and to where but this code will loop through rows 5 to 199, check if the value in column B = "Resource" and then set the corresponding value in column C, you should be able to modify for your needs but I think you definitely want a structure more like this than what the recorder generated for you..
public sub cp()
Dim ws as Worksheet
Set ws = Worksheets("Current Project Utilisation")
Dim i as int
for iI = 5 to 199
if(ws.cells(i, 2).value = "Resource") then
ws.cells(i, 3).value = "what you're copying"
end if
next I
end sub
Assuming your cell range doesn't change you can do this for the looping part
Sub ResourceCheck()
Dim WS As Worksheet
Set WS = ActiveSheet
Dim Resources() As Long, r As Long
ReDim Resources(5 To 199)
For r = 5 To 199
If UCase(WS.Cells(r, 2).Value) = "RESOURCE" Then
WS.Cells(r, 3).Value = "x"
'Do copy paste part
End If
Next r
Application.Calculate
End Sub
Can you add a sample of your data? It's a bit hard to see what you're referencing to and how the data relates to each other.
Also, where is the "Projadd" cell reference? And what does it do?
Sub CP()
' I like to know what worksheet I'm on
Dim ws as Worksheet
' if it's a dedicated worksheet use this
' Set ws = ThisWorkbook.Worksheets("Sheet1")
' Otherwise following your current code
Set ws = ActiveSheet
' I also like to grab all my data at once
Dim Data as Variant
Data = ws.Range("B6:B199")
' No need to focus the cursor
For row = 5 to 199
' No need to select any range
' Is this case-sensitive???
If Data(row-4, 1) = "Resource" Then
' Copy C6??? Paste 'ProjAdd'
ws.Cells(row, 3).Copy Range("ProjAdd")
Application.CutCopyMode = False
End If
Next
End Sub

update cell and paste it to another cell vba

I am quite new in excel vba and I would really appreciate if you can assist me.
The thing is that I have cell which updates each minute because it is linked with a function to Blomberg. The thing is that I want that each time cell updates excel copies it and pastes to another, new cell that i can observe the intra day changes.
I have come up with some codes but I can copy and paste only to one, similar cell.It looks like following:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Not Intersect(Target, Range("E4")) Is Nothing Then
Range("E4").Copy
Range("E4").PasteSpecial xlPasteValues
End If
End Sub
Any help would be highly appreciated.
If I understand your problem correctly you want to copy the value to a new cell, for logging purposes? What I would do in this case is have another sheet for logging the values named "logger_sheet" I paste a value in cell a1 when the blomberg cell updates, copy the value into my logger_sheet cell a2 when it changes copy it to a3 then a4 etc.
Here is your updated code. It assumes you have a sheet named "logger_sheet" (if you dont have one, create it) to store all the previous values. When the blomberg cell updates, it copies the value and pastes it to the next avaliable logging_sheet cell. I have developed a function that finds the last used row in a specified sheet and column. Try it out
Also there is a line you can uncomment if you want to prevent excel from flashing, I labeled it in the code
Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
target_cell = "E4"
col_to_log_data = "A"
logging_Sheet = "logger_sheet"
If Not Intersect(Target, Range("E4")) Is Nothing Then
'uncomment this line to stop the "flashing"
'Application.ScreenUpdating = False
'gets the name of the current sheet
data_sheet = Range(target_cell).Parent.Name
Range(target_cell).Select
Selection.Copy
'gets the next free row from column a of the logging sheet (the next free row is
'the last used row + 1)
next_free_row = GetLastRowByColumn(CStr(col_to_log_data), CStr(logging_Sheet)) + 1
'pastes the value
Sheets(logging_Sheet).Range(col_to_log_data & CStr(next_free_row)).PasteSpecial Paste:=xlPasteValues
Application.CutCopyMode = False
'switches back to the data sheet
Sheets(data_sheet).Select
'make sure you turn screen updating on (if it was never off it still works)
Application.ScreenUpdating = True
End If
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'this finds the last row in a specific column
'PARAMS: col_to_check, the clumn we want the last row of
' Opt: sheet_name, the sheet you want to check last row of
' default is current sheet if not specified
'RETURN: the last row number used in the sheet
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetLastRowByColumn(col_to_check As String, Optional sheet_name As String)
'gets current sheet name
the_current_sheet = ActiveSheet.Name
'if the user didnt' specify a sheet use the current one
If (Len(sheet_name) = 0) Then
sheet_name = the_current_sheet
End If
'gets last row
GetLastRowByColumn = Sheets(sheet_name).Range(col_to_check & "65536").End(xlUp).Row
'returns to original sheet
Sheets(the_current_sheet).Select
End Function
If my answer solves your problem please mark it as the solution
How about this? It will transfer E4 to Sheet2 in a new row each time E4 changes.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Target.Address = "$E$4" Then Sheets("Sheet2").Cells(Rows.Count, "F").End(xlUp).Offset(1) = Target
End Sub
I'm making the assumption you want to log every change of values.
I would advise to keep a log in a separate sheet. Let's call it LogSheet.
Sub WriteLog(ByRef r As range)
Dim Lastrow as integer
With ThisWorkBook.WorkSheets("LogSheet")
LastRow = .Cells(.Rows.Count,"A").End(XlUp).Row
.Range("A" & LastRow + 1).Value = Now & " - " & r.Value
End With
End Sub
This sub will basically write all changes in column A of our log sheet with a timestamp!
Now, we need to make changes to your code in order to tell, to make logs whenever there is a change. To do so, we're going to make a call to our function and tell to copy the content of the range("E4") (The one that gets updated all the time)
If Not Intersect(Target, Range("E4")) Is Nothing Then
'add this line
WriteLog(ActiveSheet.Range("E4"))
Try it now.

Copy and Paste in VBA using relative references? (Error Code 1004)

New to this forum so sorry if this is off. I'm trying to do a simple copying of cell values from one worksheet in a book to another worksheet, but need to use relative cell references as the number of rows that will be copy/pasted changes depending on the data inputted.
The (very simple) code so far is:
Sub SuitorList()
'Defining Variables
Dim Row As Integer
Row = Sheets("References").Cells(6, 2).Value
'Copying Statistics
Sheets("Charts").Range(Cells(1, 1), Cells(Row, 1)).Value = _
Sheets("Data").Range(Cells(1, 1), Cells(Row, 1)).Value
End Sub
This code works fine when I use absolute cell references (i.e. "B1:B7") but when I use a relative reference I receive error code 1004: Application-defined or object-defined error.
Any thoughts?
Alternative Solution:
If you are not a fan of Loops, use Worksheet.Cells Property
Sub SuitorList()
'Defining Variables
Dim Row As Integer
Set wd = ThisWorkbook.Worksheets("Data")
Set wc = ThisWorkbook.Worksheets("Charts")
Row = Sheets("References").Cells(6, 2).Value
'Copying Statistics
Range(wd.Cells(1, 1), wd.Cells(Row, 1)).Copy Destination:=Range(wc.Cells(1, 1), wc.Cells(Row, 1))
End Sub
If you are copying data from one sheet to another and the amount of data to be copied/pasted is always changing then I would do something like this. Which is filtering the data from your selection sheet then copying it and pasting it to your destination sheet by finding the first blank cell. You may have to mess with this a bit, but it is a good start.
'Defining Variables
Dim Row As Integer
Row = Sheets("References").Cells(6, 2).Value
'switches the sheet
Sheets("Charts").Select
'filters a table based on the value of the Row variable
ActiveSheet.ListObjects("Table1").range.AutoFilter Field:=1, Criteria1:= _
range("Row"), Operator:=xlAnd
'moves to the first cell in the filtered range
range("A1").Select
'selects all values in the range and copies to clipboard
range(Selection, Selection.End(xlDown)).Select
Application.CutCopyMode = False
Selection.Copy
'switches the sheet back to data sheet
Sheets("Data").Select
'finds the first blank cell in the declared range you want to paste into
ActiveSheet.range("A:A").Find("").Select
'pastes the selection
ActiveSheet.Paste
Thanks for the help. I was able to find a work around using the following code:
Sub SuitorList()
'Defining Variables
Dim Row As Integer
Row = Sheets("References").Cells(6, 2).Value
'Copying Statistics
For i = 1 To Row
Sheets("Charts").Range("A" & i).Value = Sheets("Data").Range("A" & i).Value
Next
End Sub

Excel - Select end of column + additional rows

I am trying to make a macro that selects certain data in my sheet. I have a sheet with data that is pulled into it using:
Windows("Item checkout workbook_New.xlsx").Activate
Range("A2:G300").Select
Selection.Copy
Windows("VLookup test.xlsx").Activate
Sheets("Sheet1").Select
Range("A2:G2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Sheets("Sheet1").Range("A2:G300").Copy Sheets("Sheet2").Range("A2")
Sheets("Sheet2").Select
Application.CutCopyMode = False
Once this data is input, I have two columns H2:H300 and I2:I300 that has formulas already in it for Vlookup that get information from A2:G300.
What I then need to do is select only the relevant data and copy it back to Windows("Item checkout workbook_New.xlsx"). By relevant data, I need to select only cells with data in the A2:G300 range as well as the H2:I300 cells that match. Seeing as ALL H2:I300 cells have data, I am not sure how to do this. I tried to create a macro that uses END to select all of column A and then the rows that go with it, but this is what I got and as you can see it will not work:
Range("A2").Select
Range(Selection, Selection.End(xlDown)).Select
Range("A2:I78").Select
Selection.Copy
I am not great at VBA thus it is hard to come up with things on the fly, but I feel like there should be a way to get this to work. Any advice would be great!
Range("A2").Select
Range(Selection, Selection.End(xlDown)).EntireRow.Select
Selection.Copy
Windows("Item checkout workbook_New.xlsx").Activate
Sheets("Sheet1").Select
Range("A2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Got it working!
Based off your own answer, it seems I may have misinterpreted your question. What I gathered was that you were looking for a way to select relevant cells in a worksheet. The relevant cells could belong to one of two ranges. In one range, cells that are not empty should be selected. In the other range, cells that match a value should be selected. (you can just add in your copy/paste code)
I solved that problem below.
Sub test()
'store results here
Dim result As Range
setupTest
'check this range and return items that are not empty
selectMatchingCells Range("A1:D1"), result
'check this range and return items that match value
selectMatchingCells Range("B2:C4"), result, "hi"
result.Select
End Sub
Function setupTest()
Range("A1").Value = "anything"
Range("c1").Value = "may go"
Range("D1").Value = "here"
Range("B2").Value = "hi"
Range("B3").Value = "but not here"
End Function
Function selectMatchingCells(search As Range, result As Range, Optional searchValue As String = "")
For Each cell In search
'are we checking that cell value matches string, or if cell has a value at all?
If searchValue = vbNullString Then
'check if cell is not empty
If IsEmpty(cell) = False Then selectCell result, cell
Else
'check if value matches
If cell.Text = searchValue Then selectCell result, cell
End If
Next cell
End Function
Function selectCell(result As Range, cell As Variant)
'check if result range already exists or not
If result Is Nothing Then
'make range equal to cell
Set result = cell
Else
'add cell to existing range
Set result = Union(result, cell)
End If
End Function
Please be more clear to avoid miscommunication, thanks!