How can I set the value of a cell in Cells().Select command to the value of a cell that has a formula in it? - excel

I'm trying to make a macro that copies the values inside certain cells of sheet1 and pastes then in sheet2.
This is a formula that i wrote inside cell "AI2":
=IFERROR(SUM(1+AH:AH),"0")
and it produces a number that I want to use in the macro as a variable row coordinate.
This is the code i have in my worksheet in order to trigger the macro:
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Range("AI2") <> 0 Then
Call macro1
End If
End Sub
And this is the macro:
Sub macro1()
Dim RV As Integer
RV = Sheets("sheet1").Range("AI2").Value
Cells(RR, 33).Select
Range(ActiveCell.Offset(0, -6), ActiveCell.Offset(0, -1)).Select
Selection.Copy
Sheets("sheet2").Select
Range("A1048576").Select
Selection.End(xlUp).Select
ActiveCell.Offset(1, 0).Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
If I delete the first 3 lines of code, the macro works, but I have to manually select the cell for the offsets to reference from.
I need to make it so the value of cell "AI2" is used as the first coordinate in this line of code:
Cells(RR, 33).Select
I am very new to any kind of programming, but I want to learn this in order to achieve my goals for this spreadsheet and future ones with similar functions.

I am limiting the scope of your Worksheet_Change to only fire when a change is registered in Column AH since this is the column that will trigger a formula change in Column AI
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 34 Then
If Range("AI2") <> 0 Then
Macro2
End If
End If
End Sub
Sub Macro2()
Dim cs As Worksheet: Set cs = ThisWorkbook.Sheets("Sheet1")
Dim ps As Worksheet: Set ps = ThisWorkbook.Sheets("Sheet2")
Dim xRow As Long, LR As Long
LR = ps.Range("A" & ps.Rows.Count).End(xlUp).Offset(1).Row
xRow = cs.Range("AI2").Value
cs.Range(cs.Cells(xRow, "AB"), cs.Cells(xRow, "AG")).Copy
ps.Range("A" & LR).PasteSpecial xlPasteValues
End Sub

Copy Range to First Empty Cell
Calculate
If you are using a formula in the cell range AI2 you should use the Worksheet Calculate event which will occur everytime the formula is being calculated.
Standard Module
Option Explicit
Public Const strRange As String = "AI2"
Public vntValue As Variant
Sub macro1()
Dim rng As Range ' Target Cell Range
Dim RV As Long ' Row Value
' In Target Worksheet
With ThisWorkbook.Sheets("Sheet2")
' Calculate the first empty (unused) cell in column A (A1 not included).
Set rng = .Cells(.Rows.Count, "A").End(xlUp).Offset(1)
End With
' In Source Worksheet
With ThisWorkbook.Worksheets("Sheet1")
' Write the value of Row Cell to Row Value.
RV = .Range(strRange).Value
With .Cells(RV, "AH") ' or 33
' Copy range from "AB" to "AG" in row defined by Row Value in
' Source Worksheet to the range from "A" to "F" in row of Target
' Cell Range in Target Worksheet.
rng.Resize(, 6) = Range(.Offset(0, -6), .Offset(0, -1)).Value
End With
End With
End Sub
Sheet1
Option Explicit
Private Sub Worksheet_Calculate()
If vntValue <> Range(strRange).Value Then
vntValue = Range(strRange).Value
If Range(strRange).Value <> "0" Then macro1
End If
End Sub
ThisWorkbook
Option Explicit
Private Sub Workbook_Open()
vntValue = Worksheets("Sheet1").Range(strRange).Value
End Sub
Change
If you are manually changing the values in the cell range AI2, you have to use the Worksheet Change event.
Standard Module
Option Explicit
Sub macro1()
Dim rng As Range ' Target Cell Range
Dim RV As Long ' Row Value
' In Target Worksheet
With ThisWorkbook.Sheets("Sheet2")
' Calculate the first empty (unused) cell in column A (A1 not included).
Set rng = .Cells(.Rows.Count, "A").End(xlUp).Offset(1)
End With
' In Source Worksheet
With ThisWorkbook.Worksheets("Sheet1")
' Write the value of Row Cell to Row Value.
RV = .Range("AI2").Value
' In cell at the intersection of Row Value and column "AH".
With .Cells(RV, "AH") ' or 33
' Copy range from "AB" to "AG" in row defined by Row Value in
' Source Worksheet to the range from "A" to "F" in row of Target
' Cell Range in Target Worksheet.
rng.Resize(, 6) = Range(.Offset(0, -6), .Offset(0, -1)).Value
End With
End With
End Sub
Sheet1
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const cCell As String = "AI2"
If Target = Range(cCell) Then
If Range(cCell).Value <> "0" Then macro1
End If
End Sub
Like in the Calculate version, you might also want to use a public variable (vntValue) to prevent triggering macro1 in case the value in cell range AI2 hasn't actually changed.

Related

EXCEL: How to combine values from two different column into one new column on different sheet

i am stuck with my procject again... I tried with formulas but i can t make it work or i can t make it right, and i couldn t find similar topic any where, here is the problem. As u can see in screenshot in this link https://ibb.co/FJRBxcM i have 2 worksheets, Sheet1 with some value generator, and Sheet"RadniNalog" where i copy&paste manualy certan values from Sheet1. My goal is to make it work automatically, when i paste data from another Workbook, as shown in screenshot example, i polulate range "A10:C27", range width is constant, always 3 column, but rows can change so number is X. Now i need values from "A10:A27" to copy to next empty column from left to right in Sheet"RadniNalog" from cells in 2nd row. Next i also need to copy Value from cell =F$13$ into the first row in sheet "RadniNalog" (on screenshot example its cell "E1" and that value from F13 needs to act like a Header for values belove it. If Value from header is the same as value in cell "F13" i need to continue adding values under existing ones, and if not move to the next available column. In screenshot example, if cell "D1" from sheet "RandiNalog" is same as cell "F13" in Sheet1, then values from range "A10:A27" should be added under last value in ColumnD. I need some VBA code if possible to make it work as wanted. Thanks in advance
Copy this code to Sheet1 module
This code runs the macro copyValuesToWs when you put the code in F13
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("F13:G13")) Is Nothing Then
Application.ScreenUpdating = False
Application.EnableEvents = False
Call copyValuesToWs
Application.EnableEvents = True
Application.ScreenUpdating = True
End If
End Sub
Create a new module and insert this code
Option Explicit
Function FindLastRow(ByVal Col As Byte, ws As Worksheet) As Long
FindLastRow = ws.Cells(Rows.Count, Col).End(xlUp).Row
End Function
Function FindLastColumn(ByVal rw As Byte, ws As Worksheet) As Long
FindLastColumn = ws.Cells(rw, Columns.Count).End(xlToLeft).Column
End Function
Sub copyValuesToWs()
Dim ws1 As Worksheet: Set ws1 = Sheets("Sheet1")
Dim ws2 As Worksheet: Set ws2 = Sheets("Radni nalog")
Dim lCol As Long
Dim lRow As Long
Dim srcRng As Range
Dim dstRng As Range
Dim hdRng As Range
' Next row after ID
Dim idRng As Range: Set idRng = ws1.Range("A10")
' find last row value in column A
lRow = FindLastRow(1, ws1)
' range to be copied
Set srcRng = ws1.Range(ws1.Cells(idRng.Row, 1), ws1.Cells(lRow, 1))
' find last used column in sheet2
lCol = FindLastColumn(1, ws2)
' header range
Set hdRng = ws2.Range(ws2.Cells(1, 1), ws2.Cells(1, lCol))
' check if value exists in header
On Error Resume Next
Dim sValue As Double: sValue = Application.WorksheetFunction.Match(ws1.Range("F13").Value, hdRng, 0)
If Err.Number = 0 Then ' value exists
' find last row
Set dstRng = ws2.Cells(FindLastRow(sValue, ws2) + 1, sValue)
' paste values
srcRng.Copy
dstRng.PasteSpecial xlPasteValues
Else
' set destination range
Set dstRng = ws2.Cells(2, lCol + 1)
' set header value
ws1.Range("F13:G13").Copy
ws2.Cells(1, lCol + 1).PasteSpecial xlPasteValues
' paste values
srcRng.Copy
dstRng.PasteSpecial xlPasteValues
End If
On Error GoTo 0
Application.CutCopyMode = False
End Sub

Sort ascending/descending in Excel using VBA sub

I want to sort an amount of data in Excel. It should toggle between ascending and descending on every click.
I'd found this problem solved in the next thread:
sort ascending/descending vba excel.
But I want to do some changes in the code.
I want to sort using the current column where I clicked (the headers). I don't know if this is possible using just one macro and sending the cell where I call the event.
Here is the code that I'm using:
Worksheet (where I call the Sub):
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Selection.Count = 1 Then
If Not Intersect(Target, Range("A2:C2")) Is Nothing Then
Call sort_table(Target)
End If
End If
End Sub
Sub:
Sub sort_by_letters(Order As Range)
Dim dataRange As Range
Dim fieldOrder As Range
Dim xlSort As XlSortOrder
Dim LastRow As Long
With ActiveSheet
Set LastRow = .Cells(.Rows.Count, Order).End(xlUp).Row
End With
If (Order.Value > Range(Column(Order) & CStr(LastRow))) Then
xlSort = xlAscending
Else
xlSort = xlDescending
End If
Set dataRange = Range("A2:C" & LastRow)
Set campoOrden = Order
dataRange.Sort key1:=fieldOrder, order1:=xlSort, Header:=xlYes
End Sub
Sort on Selection Change
Sheet Module e.g. Sheet1
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Selection.Count = 1 Then
If Not Intersect(Target, Range(strHeaders)) Is Nothing Then
SortTable Target
End If
End If
End Sub
Standard Module e.g. Module1
Public Const strHeaders As String = "A2:C2"
Sub SortTable(Target As Range)
Dim LuCell As Range ' Last Used Cell Range
Dim rngS As Range ' Sort Range
Dim xlSort As XlSortOrder ' Sort Order
' In Target Worksheet
With Target.Worksheet
' Calculate last used cell in Target Column.
Set LuCell = .Cells(.Rows.Count, Target.Column).End(xlUp)
' Check if value in first row below Headers in Target Column is greater
' than value in Last Used Cell Range.
If Target.Offset(1) > LuCell Then
xlSort = xlAscending
Else
xlSort = xlDescending
End If
' In Headers Range
With .Range(strHeaders)
' Calculate Sort Range.
' Create a reference to Sort Range.
Set rngS = .Resize(LuCell.Row - .Row + 1)
End With
End With
' Sort Sort Range.
rngS.Sort Key1:=Target, Order1:=xlSort, Header:=xlYes
End Sub

Transferring rows into another sheet

I am trying to transfer two rows of Sheet1 (randomly and based on certain criteria) into Sheet3.
The values in cells "P2" and "P5" indicate the row number to be transferred, and column "A" has row numbers.
There's no possibility that values in "P2" and "P5" could match multiple rows in column "A". They should match 1 row each, so only one row should be copied per "P2" and "P5". Yet, sometimes I see multiple rows getting copied.
Below is the code:
Sub copyrows()
Dim tfRow As Range, cell As Object
Set tfRow = Range("A1:A") 'Range which includes the values
For Each cell In tfRow
If IsEmpty(cell) Then
Exit Sub
End If
If cell.Value = Range("P2").Value Then
cell.EntireRow.Copy
Sheet3.Select 'Target sheet
ActiveSheet.Range("A65536").End(xlUp).Select
Selection.Offset(1, 0).Select
ActiveSheet.Paste
End If
Next
End Sub
Sub copyrows2()
Dim tfRow2 As Range, cell As Object
Set tfRow2 = Range("A1:A") 'Range which includes the values
For Each cell In tfRow2
If IsEmpty(cell) Then
Exit Sub
End If
If cell.Value = Range("P5").Value Then
cell.EntireRow.Copy
Sheet3.Select 'Target sheet
ActiveSheet.Range("A65536").End(xlUp).Select
Selection.Offset(1, 0).Select
ActiveSheet.Paste
End If
Next
End Sub
As #urdearboy mentioned in the commnets above, you need to add a row to your second A column range to avoid getting the error.
To merge two conditions, in your case add an Or to your If.
To run the code faster, don't Select and Activate different sheets, it takes a long time for the code to run. Instead, use a Range object, like CopyRng and every time the if criteria is ok, you add that cell to the range using the Union function.
Read HERE about the Union functionality.
More comments inside the code's notes below.
Modified Code
Option Explicit
Sub copyrows()
Dim Sht1 As Worksheet, Sht3 As Worksheet
Dim tfRow As Range, C As Range ' use Range not Object, also try not to use Cell it's close to Cells
Dim CopyRng As Range
Dim LastRow As Long
Set Sht1 = Sheet1
Set Sht3 = Sheet3
With Sht1
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row ' get last row with data in column A
Set tfRow = .Range("A1:A" & LastRow) 'Range which includes the values
For Each C In tfRow
If IsEmpty(C) Then
Exit Sub
End If
If C.Value = .Range("P2").Value Or C.Value = .Range("P5").Value Then ' use Or to combine both scenarios
If Not CopyRng Is Nothing Then
Set CopyRng = Application.Union(CopyRng, C) ' use Union to merge multiple ranges
Else
Set CopyRng = C
End If
End If
Next C
End With
' make sure there is at least one cells in your merged range
If Not CopyRng Is Nothing Then
' get last row with data in "sheet3"
LastRow = Sht3.Cells(Sht3.Rows.Count, "A").End(xlUp).Row
CopyRng.EntireRow.Copy Destination:=Sht3.Range("A" & LastRow + 1)
End If
End Sub

Excel if value in range is larger than value in a cell, clear value of cell in range

I want to type a number in B3. If a number in the range B8 to B200 is larger than the value in B3, the cell in the range whose value is larger than that of B3's value will be cleared of its contents. (I tried doing this with the code attached)
(OR:
If a value is entered in B3, a drop down of all the values that are less than or equal to the value in B3 is generated (that way there is no way to exceed the value in B3).)
Sub ProcessLineNumberValidation()
Dim QTY As Integer
Dim ProcessNum As Integer
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Ozone Generator")
QTY = ws.Sheets("Ozone Generator").Cells(3, 2).Value
For i = 8 To 200
ProcessNum = ws.Sheets("Ozone Generator").Cells(i, 2).Value
If ProcessNum > QTY Then
ws.Sheets("Ozone Generator").Cells(i, 2).ClearContents
End If
Next i
End Sub
First, you use Set ws = Thisworkbook.Sheets("Ozone Generator")
Then, you use ws.Sheets("Ozone Generator") on multiple lines which is the likely source of your problem. If you substitute ws back in to the above line of code you get:
Thisworkbook.Sheets("Ozone Generator").Sheets("Ozone Generator")
Which is not a valid cell reference. Just use ws.Cells(.... which will result in the below code (corrected for problem and applied more standard spacing, ordering, & indentation methods to code)
Option Explicit
Sub ProcessLineNumberValidation()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Ozone Generator")
Dim QTY As Integer, ProcessNum as Integer, i
QTY = ws.Cells(3, 2).Value
For i = 8 To 200
ProcessNum = ws.Cells(i, 2).Value
If ProcessNum > QTY Then
ws.Cells(i, 2).ClearContents
End If
Next i
End Sub
You can consider this alternative that has the same output but will be quicker. For Each loops are faster than For i = loops when looping through ranges like this. Also toggling off ScreenUpdating will make this look cleaner from a user standpoint.
Sub ProcessLineNumberValidation()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Ozone Generator")
Dim MyRange As Range: Set MyRange = ws.Range("B8:B200")
Dim MyCell As Range
Application.ScreenUpdating = False
For Each MyCell In MyRange
If MyCell > ws.Cells(3, 2) Then MyCell.ClearContents
Next MyCell
Application.ScreenUpdating = True
End Sub
this could be a work for Autofilter():
Sub ProcessLineNumberValidation()
With ThisWorkbook.Sheets("Ozone Generator").Range("B7:B200") 'reference your sheet range B7:B200 (B7 is the header, values are from B8 downwards)
.AutoFilter field:=1, Criteria1:=">" & .Parent.Range("B3").Value2 ' filter referenced range with values greatre than referenced range sheet cell B3
If Application.WorksheetFunction.Subtotal(103, .Resize(, 1)) > 1 Then .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).ClearContents ' clear any filtered cell other than header
.Parent.AutoFilterMode = False ' remove autofilter
End With
End Sub
and if you want ProcessLineNumberValidation() being called on every "Ozone Generator" sheet B3 cell change then place this code in that sheet code pane:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$3" Then 'if cell B3 has changed
Application.EnableEvents = False ' disable events to prevent this event handler being called in a possibly infinite loop
ProcessLineNumberValidation ' process your range
Application.EnableEvents = True ' enable events back on
End If
End Sub

How to Lock cell at selected Last Row?

Private Sub Worksheet_Change(ByVal Target As Range)
Dim lastRow As Long
lastRow = ActiveSheet.Cells(Rows.Count, "E").End(xlUp).Row
ActiveSheet.Unprotect
lastRow.Locked = True
ActiveSheet.Protect
End Sub
*I already run this code. But still not lock the last row.
*When add "MsgBox lastrow" its working and show correct selected row.
*Thank You
Open This For More Info ----> Excel View With Msg Box
In case your cell in Column E is part of a merged cells (in your case Columns E:K are merged), then you set a new Range with the variable MergedCell to the merged area, and then Lock the entire range of merged cells.
Code
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim lastRow As Long, cell As Range, MergedCell As Range
' find last row in Column E
lastRow = ActiveSheet.Cells(Rows.Count, "E").End(xlUp).Row
ActiveSheet.Unprotect
Set cell = Range("E" & lastRow)
' if cell in Column E is part of merged cells
If cell.MergeCells = True Then
Set MergedCell = cell.MergeArea
MergedCell.Locked = True
Else
cell.Locked = True
End If
ActiveSheet.Protect
End Sub

Resources