I want to run a Worksheet_change function that will collect the cell references of any changed cells into an array of "Cells" objects but I keep getting the error "Type mismatch". This is what i've got so far:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim arArray(1 To 70) As Range
Dim K As Integer
K = 1
For i = 1 To 70
For j = 2 To 14
If Target.Column = j And Target.Row = i Then
Set arArray(K) = Target.Address
K = K + 1
End If
Next j
Next i
End Sub
Currently the code looks for any changes within the grid B1 to N70 and stores the changed cell if a change has occurred to a cell within that grid.
Any help would be greatly appreciated.
Right now, your code is set to look over many cells every time any cell changes. Based on your initial description, I'm sure that this is not what you really want. In the following code, Worksheet_Change keeps track of each cell that gets changed in B1:N70 by putting its address in a collection named "changed_cells". While "show_changes" prints the address of the cells that got changed to the immediate window.
Option Explicit
Dim changed_cells As New Collection
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Range("B1:N70"), Target) Is Nothing Then
changed_cells.Add Target.Address(False, False)
End If
End Sub
Private Sub show_changes()
Dim x As Long
For x = 1 To changed_cells.Count
Debug.Print changed_cells(x)
Next
End Sub
Note: If the immediate window is not visible, press ctrl+g to see the ouptut
You declared an array of Range objects at the top and the Target.Address property returns a string.
Your line
Set arArray(K) = Target.Address
Should be
Set arArray(K) = Range(Target.Address)
Related
I am not sure whether this is running, has errors, or whether the variables are correct. I followed steps online to check what my variables are, like typing ?variable in the immediate window, checking the locals window, and hovering my mouse over the variable, but nothing comes up.
Nothing happens regardless when I go back to the workbook.
Here's a screenshot:
Included a screenshot because the problem might not be just with the code.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.address = "C5:I5" Then
Dim row As Integer
row = Application.WorksheetFunction.Match(ActiveCell.Offset(0, -1).Value, Range("$n$1:$n$365"), 0)
Dim address As Long
address = Application.WorksheetFunction.address(row, 15)
Range(address).Value = Range(address).Value + 1
ActiveCell.Value = Range(address).Value
End If
End Sub
The purpose is to add 1 to the value of the active cell when clicked. The cell's value will change based on the date in the cell directly above it; the value needs to be tied to the date. I plan to accomplish this using a hidden array of ascending dates and values, located at n1:o365.
(a) Probably your intention is to check if the target cell is within the range "C5:I5" - what your checking is if target has the address "C5:I5" so the if fails.
Use for example the function Intersect for that
(b) (Minor thing) Declare row as Long
(c) There is no .WorksheetFunction.address function. A Range has an Address property, eg Target.Address. Note that this will return a String, not a Long. But you don't need this anyhow. Use Cells if you know row and column of a cell.
Note that I haven't checked your logic to find the correct row.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Intersect(Target, Range("C5:I5")) Is Nothing Then Exit Sub
Dim row As Long
On Error Resume Next
row = Application.WorksheetFunction.Match(Target.Offset(0, -1).Value, Range("$n$1:$n$365"), 0)
On Error GoTo 0
If row = 0 Then Exit Sub ' Row not found
Dim cell As Range
Set cell = Cells(row, 15)
cell.Value = cell.Value + 1
Target.Value = cell.Value
End Sub
I have a set of data:
I have data validation set up for entering Y or N within the "more issues Column".
I need a row to be inserted under that when Y is selected, without having to run a macro.
I am running Excel 2016.
Try this macro: place in the worksheet object.
*Updated
Private Sub Worksheet_Change(ByVal Target As Range)
'If the cell already has a capital "Y" and you
'double click the cell it will insert a row.
'And typing a "Y" into any other column will not error
If Target.Cells.Count > 1 Then Exit Sub
If Not Intersect(Target, Columns(2)) Is Nothing Then
If Target.Value = "Y" Then
Target.Offset(1).EntireRow.Insert Shift:=xlDown
End If
End If
End Sub
Here's some working code to get you started. Just place the code in the sheet you are using by right clicking the sheet tab and selecting view code.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range, sh As Worksheet
Set sh = ThisWorkbook.Sheets("Sheet1")
If Not Application.Intersect(Range("B2:B8"), Range(Target.Address)) Is Nothing Then
Set r = Target
If r = "Y" Then r.Offset(1, 0) = "populated cell"
End If
End Sub
The animated gif (click to see detail) show entering N or Y and having the cell below only Y's populated. Ask if you have questions about how this works.
I am creating a model in Excel in which a cell computes the sum of two cells and keeps adding to the value every time the two cells on which it is dependent change values. For example,
If,
A + B = C
Then,
Instance 1: -> 5 + 5 = 10
Instance 2: -> 4 + 3 = 17
Instance 3: -> 2 + 3 = 22
and so on...
I believe this can be achieved through a VB script.
you only need to put the following code in the worksheet code pane:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Range("A1:A2"), Target) Is Nothing Then Exit Sub
Range("B1") = Range("B1") + WorksheetFunction.sum(Range("A1:A2"))
End Sub
of course you have to change:
all "A1:A2" occurrences to your actual cells to sum address
all "B1" occurrences to your actual cell holding the running sum address
Hold the running total in a Public variable (total). Initialize this as the workbook opens, using the workbook_open event, to the sum of the two cells of interest. Then use a worksheet_change event to monitor changes to those two cells and, if either changes, add their new value to the existing value of total. I have used cell C1 to show the running total.
In a standard module:
Option Explicit
Public total As Long
Public targetCell As Range
In the ThisWorkbook code pane
Option Explicit
Private Sub Workbook_Open()
With ThisWorkbook.Worksheets("Sheet1")
Set targetCell = .Range("C1")
total = Application.WorksheetFunction.Sum(.Range("A1:B1"))
targetCell = total
End With
End Sub
In the worksheet code pane where the cells to monitor are
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Range("A1")) Is Nothing Then
total = total + Target
targetCell = total
End If
If Not Application.Intersect(Target, Range("B1")) Is Nothing Then
total = total + Target
targetCell = total
End If
End Sub
Or correctly do what #DisplayName has done! I wrote this initially for a Debug.Print of total (not writing to cell) and forgot to re-factor.
I've managed to write a code that detects value changes of particular cells in any worksheet, but I've struggled to construct something that detects and keeps track of ranged (value) changes.
For example, if a user decides to copy and paste some range of data (lets say more than 1 cell), it will not get caught by the macro. Same goes for a user selecting a range and then manually entering values into each cell while range is still selected.
My current code is constructed of 2 macros, the first runs anytime a worksheet selection change occurs and it stores the target.value into a previous value variable. The second macro runs anytime a worksheet change occurs and it tests if the targeted value is different than the previous one, if so it then notifies the user of the change that had occurred.
OK I don't really see anything here which covers the whole thing, so here's a rough attempt.
It will handle single or multi-cell updates (up to some limit you can set beyond which you don't want to go...)
It will not handle multi-area (non-contiguous) range updates, but could be extended to do so.
You likely should add some error handling also.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Where As String, OldValue As Variant, NewValue As Variant
Dim r As Long, c As Long
Dim rngTrack As Range
Application.EnableEvents = False
Where = Target.Address
NewValue = Target.Value
Application.Undo
OldValue = Target.Value 'get the previous values
Target.Value = NewValue
Application.EnableEvents = True
Set rngTrack = Sheets("Tracking").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
'multi-cell ranges are different from single-cell ranges
If Target.Cells.CountLarge > 1 And Target.Cells.CountLarge < 1000 Then
'multi-cell: treat as arrays
For r = 1 To UBound(OldValue, 1)
For c = 1 To UBound(OldValue, 2)
If OldValue(r, c) <> NewValue(r, c) Then
rngTrack.Resize(1, 3).Value = _
Array(Target.Cells(r, c).Address, OldValue(r, c), NewValue(r, c))
Set rngTrack = rngTrack.Offset(1, 0)
End If
Next c
Next r
Else
'single-cell: not an array
If OldValue <> NewValue Then
rngTrack.Resize(1, 3).Value = _
Array(Target.Cells(r, c).Address, OldValue, NewValue)
Set rngTrack = rngTrack.Offset(1, 0)
End If
End If
End Sub
"Undo" part to get the previous values is from Gary's Student's answer here:
Using VBA how do I detect when any value in a worksheet changes?
This subs will work for you but you have just implement codes in every sheet manually. Just need to copy paste. See below screenshot which is for 1 sheet Sheet1
(1) Declare a public variable.
Public ChangeTrac As Variant
(2) Write below codes in Worksheet_SelectionChange event
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
ChangeTrac = Target.Value
End Sub
(3) write below codes in Worksheet_Change event
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Application.Intersect(Target, Cells()) Is Nothing Then
If ChangeTrac <> Target.Value Then
MsgBox "Value changed to Sheet1 " & Target.Address & " cell."
Range(Target.Address).Select
End If
End If
End Sub
Then test by changing data in any cell. It will prompt if any cell value is changed.
I try to write a macro that on double click of a cell, inserts a new row below that cell with some formulas. The important thing for me is that if I double click the cell again, then the formulas of the previously inserted line are updated with the right indexes.
For example, in the code below, double click A1 will insert the formula =B2+1 in line 2. Double clicking again should insert the same in line 2. But now line 2 shifter to line 3, so the formula in A3 should be =B3+1.
Here is the code I have so far:
Option Explicit
Const MYRANGE As String = "A:A"
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
'If Sh.Name <> "Sheet1" Then Exit Sub
If Target.Cells.Count > 1 Then Exit Sub
If Intersect(Target, Sh.Range(MYRANGE)) Is Nothing Then Exit Sub
Cancel = True
Target.Rows(2).Insert
Dim newRow As Range
Set newRow = Target.Rows(2)
Dim rowIndex As Long
rowIndex = newRow.row
newRow.Cells(1, 1).Formula = "=B" & rowIndex & "+1"
End Sub
UPDATE: Changing Target.Rows(2).Insert to Target.Offset(1).EntireRow.Insert solves the issue. Leaving the question open for explanations on what is Offset and how it differs from Rows (The property EntireRow does not exist for Rows(2))
You can reduce this code by four lines for the same outcome, pls see below
Note though that your code is updating cells in your target row and below, ie it won't be updating any cell formulae outside column A that reside above your target. Which is probably not an issue but worth mentioning. If you wanted a full update then you would always insert at row2 rather than at target
Option Explicit
Const MYRANGE As String = "A:A"
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, ByVal Target As Range, Cancel As Boolean)
If Target.Cells.Count > 1 Then Exit Sub
If Intersect(Target, Sh.Range(MYRANGE)) Is Nothing Then Exit Sub
Cancel = True
Target.Offset(1).EntireRow.Insert
Target.Offset(1).Formula = "=B" & Target.Row + 1 & "+1"
End Sub