I am trying to write a macro that will update all cells in a column that have the same value as the adjacent column below are before and after of what I am trying to accomplish. In this example you would update B1 and then any cells in A1 with the same value would update to the B1 value
Here is the code I am using
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Dim cel As Range
Set rng1 = Range("A1", Range("A2").End(xlDown))
For Each cel In rng1
If cel = Target.Offset(0, -1).Value Then
cel.Offset(0, 1).Value = Target.Value
End If
Next cel
End Sub
I am not sure if what I wrote is correct, but I keep getting out of stack space error, which I think is from the macro continuously looping every time through changing the same cells. I believe this should be possible but I am a little lost.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column <> 2 Then Exit Sub
Application.ScreenUpdating = False
For Each cel In Range("A1:A" & Range("A" & Rows.Count).End(xlUp).Row)
If cel = Target.Offset(, -1) Then
cel.Offset(, 1) = Target
End If
Next cel
Application.ScreenUpdating = True
End Sub
I would try to avoid looping if possible. Perhaps use a UDF instead, using the .Find() method?
Option Explicit
Function myLookup(ByVal rng As Range) As String
Application.Volatile
Dim ws As Worksheet, lookupRng As Range, retRng As Range
Set ws = rng.Parent
With ws
Set lookupRng = .Range(.Cells(1, rng.Column), .Cells(rng.Row - 1, rng.Column))
End With
Set retRng = lookupRng.Find(rng.Value, ws.Cells(1, rng.Column))
If retRng Is Nothing Then
myLookup = vbNullString
Else
With retRng
myLookup = ws.Cells(.Row, .Column + 1)
End With
End If
End Function
You would place this UDF in the worksheet as follows:
and fill down. This will prevent circular references because it will search for the cells above it only within the lookupRng.
And, the final result:
Related
I want to select only cells that contains data in specific range (C7:I15). Code below can do that only for column "G". How to change code for my range?
Sub Testa()
Dim LR As Long, cell As Range, rng As Range
With Sheets("Sheet1")
LR = .Range("G" & Rows.Count).End(xlUp).Row
For Each cell In .Range("G2:G" & LR)
If cell.Value <> "" Then
If rng Is Nothing Then
Set rng = cell
Else
Set rng = Union(rng, cell)
End If
End If
Next cell
rng.Select
End With
End Sub
You can use a generic function to which you pass the range that should be checked - and which returns a range with the non-empty cells (see update below for function using SpecialCells instead of iteration)
Public Function rgCellsWithContent(rgToCheck As Range) As Range
Dim cell As Range
For Each cell In rgToCheck
If cell.Value <> "" Then
If rgCellsWithContent Is Nothing Then
Set rgCellsWithContent = cell
Else
Set rgCellsWithContent = Union(rgCellsWithContent, cell)
End If
End If
Next cell
End Function
You can use this sub like this:
Sub Testa()
With ThisWorkbook.Worksheets("Sheet1")
'select cells in range C7:I15
rgCellsWithContent(.Range("C7:I15")).Select
'select cells in column G
Dim LR As Long
LR = .Range("G" & Rows.Count).End(xlUp).Row
rgCellsWithContent(.Range("G2:G" & LR)).Select
'you can even combine both
Dim rgNew As Range
Set rgNew = rgCellsWithContent(.Range("C7:I15"))
Set rgNew = Union(rgNew, rgCellsWithContent(.Range("G2:G" & LR)))
rgNew.Select
End With
End Sub
UPDATE:
This function uses the SpecialCells command.
You can make a difference to return values only or to return values and formulas.
Public Function rgCellsWithContent(rgToCheck As Range, _
Optional fValuesAndFormulas As Boolean = True) As Range
Dim cell As Range
On Error Resume Next 'in case there are no cells
With rgToCheck
Set rgCellsWithContent = .SpecialCells(xlCellTypeConstants)
If fValuesAndFormulas Then
Set rgCellsWithContent = Union(rgCellsWithContent, .SpecialCells(xlCellTypeFormulas))
End If
End With
On Error GoTo 0
End Function
If no formulas in the range where selection should be done, you can use the next compact code, not needing any iteration:
Dim rng As Range
On Error Resume Next 'for the case of no any empty cell
Set rng = Range("C7:I15").SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If Not rng Is Nothing Then rng.Select
The next version is able to deal with formulas, too:
Dim rng As Range, rngSel As Range, arrFormula
Set rng = Range("C7:I15")
With rng
arrFormula = .Formula
.Value = .Value
On Error Resume Next
Set rngSel = .SpecialCells(xlCellTypeConstants)
On Error GoTo 0
.Formula = arrFormula
End With
If Not rngSel Is Nothing Then rngSel.Select
I have a template Pricelist, were there are about 2600 rows, from this based on one column you pick what products you want.
I want to copy these rows into a new sheet.
Use the following code, but does some things it shouldn't.
Any suggestions?
Private Sub CmdAdd_Click()
Dim rng As Range
Dim cel As Range
Set rng = Range("B8:B39")
For Each cel In rng
If cel.Value = "X" Then
cel.EntireRow.Select
Application.CutCopyMode = False
Selection.Copy Destination:=Sheets("NewPricelist").Range("A" & Rows.Count).End(xlDown).Offset(1, 0)
End If
Next cel
End Sub
I believe the issue you are facing is due to xlDown.
You go from rows.count (end of worksheet) and down...
If we make that xlUp then the code copies the rows to the other sheet as expected. (if that is the expected)
Private Sub CmdAdd_Click()
Dim rng As Range
Dim cel As Range
Set rng = Range("B8:B39")
For Each cel In rng
If cel.Value = "X" Then
'cel.EntireRow.Select
'Application.CutCopyMode = False
cel.EntireRow.Copy Destination:=Sheets("NewPricelist").Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
End If
Next cel
End Sub
I also commented out the select to make the code faster
I have tested your code, but by the looks of it you are pasting the row all the way down in the bottom of the worksheet. On row 1048576, and then overwriting the values.
I take it you want to paste them in an order on the top of your worksheet?
Private Sub CmdAdd_Click()
Dim rng As Range
Dim cel As Range
Dim icount As Integer
Set rng = Range("B8:B39")
icount = 0
For Each cel In rng
If cel.Value = "X" Then
icount = icount + 1
cel.EntireRow.Select
Application.CutCopyMode = False
Selection.Copy
Selection.Copy Destination:=Sheets("NewPricelist").Range("A" & 0 + icount)
End If
Next cel
End Sub
Sub Macro5()
Dim rng As Range
Set rng = Selection
For Each cell In rng
ActiveCell.Value = ActiveCell.Value + 1
Next
End Sub
Quick fix for your code would be
Sub Macro5()
Dim rng As Range
Set rng = Range("B2:B10")
Dim cell As Range
For Each cell In rng
cell.Value = cell.Value + 1
Next
End Sub
Update: By the comment I guess you would like to use the SelectionChange Event. Put the following code into the code module of the sheet
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
On Error GoTo EH
Application.EnableEvents = False
Dim rg As Range
Set rg = Range("B2:B12")
If Not (Intersect(rg, Target) Is Nothing) Then
Dim sngCell As Range
' This will only increase the values of the selected cells within B2:B10
' Not sure if this is wanted. Otherwise just modify according to your needs
For Each sngCell In Intersect(Target, rg)
sngCell.Value = sngCell.Value + 1
Next sngCell
End If
EH:
Application.EnableEvents = True
End Sub
Update 2: If you want to run the code via a button put the following code into a standard module and assign it to a button you create on the sheet
Sub Increase()
On Error GoTo EH
Application.EnableEvents = False
Dim rg As Range
Set rg = Range("B2:B10")
If Not (Intersect(rg, Selection) Is Nothing) Then
Dim sngCell As Range
For Each sngCell In Intersect(Selection, rg)
sngCell.Value = sngCell.Value + 1
Next sngCell
End If
EH:
Application.EnableEvents = True
End Sub
Test if the current cell is within your range!
Sub Macro5()
Dim rng As Range
Dim fixed_rng As Range
Set rng = Selection
Set fixed_rng = Range("B1:B10")
if Application.Union(rng, fixed_rng) = fixed_rng then
For Each cell In rng
ActiveCell.Value = ActiveCell.Value + 1
Next
End If
End Sub
I'm trying to find a last row until next highlighted cell and clear the range.
Range("B2").End(xlDown) won't work, I found something called xlCellTypeSameFormatConditions under SpecialCells but not sure how this could be applied.
Maybe there is a better method?
The result should clear Range B2:B7 only
Ok so combining both solution into one I have it like this
Private Sub WorkSheet_Change(ByVal Target As Range)
If Target.CountLarge > 1 Then Exit Sub
If Not Intersect(Target, Range("A1")) Is Nothing Then
Dim rngCheck, rngCell As Range
Set rngCheck = ActiveSheet.Range("B2:B" & Cells(2, 2).End(xlDown).Row)
For Each rngCell In rngCheck
If rngCell.Interior.Pattern = xlNone Or rngCell.Value = "" Then rngCell.Value = ""
Next
Set rngCheck = Nothing
End If
End Sub
So basically when value in "A1" changes, trigger a clear.
The same code works under Module but not with WorkSheet_Change
You could try:
Sub test()
Dim rng As Range
With Application.FindFormat
.Clear
.Interior.Color = vbWhite
End With
With ThisWorkbook.Sheets("Sheet1") 'Change to correct sheetname
Set rng = .Range("B2:B" & .Cells(.Rows.Count, "B").End(xlUp).Row)
rng.Cells.Replace What:="*", Replacement:="", SearchFormat:=True
End With
End Sub
If you want to run the code on a sheet change event try the below:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Debug.Print Target.Address
Application.EnableEvents = False
If Target.Address = "$A$1" Then
With Application.FindFormat
.Clear
.Interior.Color = vbWhite
End With
Set rng = Range("B2:B" & Cells(2, 2).End(xlDown).Row)
rng.Cells.Replace What:="*", Replacement:="", SearchFormat:=True
End If
Application.EnableEvents = True
End Sub
Try this, note there is no exception or error handling. This will stop as soon as it hits a highlighted cell no matter what colour, and will not remove non-highlighted cells which are between highlighted cells.
Sub MoveToNextHighlightedCell()
Do Until Not ActiveCell.Interior.Pattern = xlNone Or ActiveCell.Value = ""
ActiveCell.Value = ""
ActiveCell.Offset(1, 0).Select
Loop
End Sub
Alternatively use this, it will not stop unless there are missing values. Updated as per comment from #Mikku.
Sub MoveToNextHighlightedCell()
Dim rngCheck, rngCell As Range
Set rngCheck = ActiveSheet.Range(ActiveCell, ActiveCell.End(xlDown))
For Each rngCell In rngCheck
If rngCell.Interior.Pattern = xlNone Or rngCell.Value = "" Then rngCell.Value = ""
Next
Set rngCheck = Nothing
End Sub
So to make this simple. I have Cells A,B,C,D
Cell D = B-C
B is basically apples won, and C is apples lost for explanation purposes. D is net apples.
I want to make it so that I can enter a number of apples won into cell A, and then it will add that number into Cell B, then clear the A or allow me to clear it while retaining Cell B value of B+A.
Thank you
Only with code
If you:
right click you sheet tab
View Code
copy and paste the code below
Then cells B1 to B5 will keep a running total of all the corresponding values in A1 to A5. Change this line Set rng1 = Intersect(Target, Range("A1:A5")) to set the range which the code works on (running totals are added to the immediate right)
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Dim rng2 As Range
Set rng1 = Intersect(Target, Range("A1:A5"))
If rng1 Is Nothing Then Exit Sub
Application.EnableEvents = False
For Each rng2 In rng1.Cells
rng2.Offset(0, 1).Value = rng2.Offset(0, 1).Value + rng2.Value
Next
Application.EnableEvents = True
End Sub
[updated - for your additional query you could try this]
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Dim rng2 As Range
Application.EnableEvents = False
Set rng1 = Intersect(Target, Range("A1:A5"))
If Not rng1 Is Nothing Then Call UpdateCells(rng1, 1)
Set rng1 = Intersect(Target, Range("D1:D5"))
If Not rng1 Is Nothing Then Call UpdateCells(rng1, 2)
Application.EnableEvents = True
End Sub
Sub UpdateCells(ByVal rng1, lngCol As Long)
Dim rng2 As Range
For Each rng2 In rng1.Cells
rng2.Offset(0, lngCol).Value = rng2.Offset(0, lngCol).Value + rng2.Value
Next
End Sub