I have this certain code on a worksheet event cell change. It finds certain data that I have on a Worksheet when I type an id_parameter on cell A1.
After data is found, it writes it on this worksheet.
Now I'd like to run a different macro when I change the values on column C of the data.
I'm not able to find the proper procedure. Do_something() receives the value changed in column C. I hope I explained it clearly enough.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A1")) Is Nothing Then
Call Search_data
End If
'Data is written in B2:E10
If Not Intersect(Target, Range("C2:C10")) Is Nothing Then
Call Do_something(Target.Value)
End If
End Sub
The code you have posted works as intended. The issue is most probably due to Search_Data and or Do_Something.
You change the cell A1 which then changes all cells from B2:E10. Including the changed C2:C10 so make sure that the change_event cannot be triggered again by this.
Option Explicit
Public EventsDisabled As Boolean
Private Sub Worksheet_Change(ByVal Target As Range)
If Not EventsDisabled Then
EventsDisabled = True
If Not Intersect(Target, Range("A1")) Is Nothing Then
Call search_data
End If
'Data is written in B2:E10
If Not Intersect(Target, Range("C2:C10")) Is Nothing Then
Call do_something(Target.Value)
End If
End If
End Sub
The Public variable EventsDisabled will make sure that the change event runs when a user input is given but not if a Worksheet_Change event changes the worksheet. Otherwise you will run into all sorts of weird loopings which might be infinite or at least take a long time. Your issue will most probably also be related to this. Make sure that your Do_Something sub has the right input type. You should set a few breakpoints and open the local window under:
view>local window here you can see all variables and objects and their type. You can also type:
debug.print typename(Target.value)
into the direct window and then see what type you need to type into the Do_Something signature.
Related
I have read many posts around this topic, however nothing seems to work for my scenario
I would like to Call Sub upon cell change (B2) which contains live data feed from external source -last updated:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("B2")) Is Nothing Then
Call SubName
End If
End Sub
I went through numerous posts suggesting to check if Äpplication.EnableEvents = True, or create function to detect the change ( which does work, however I cannot call sub within function) - with no success.
Interestnigly enough, when I click on B2 and press enter - it executes the sub
Thanks
Say cell A1 is updated by streaming. The update will not trigger either:
Worksheet_SelectionChange
Worksheet_Change
What you need to do is setup an equation somewhere:
=A1
When A1 is refreshed, the formula cell will re-calculate and you can detect it with the Calculate Event.
you can simply go
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$B$2" Then SubName
End Sub
I want to get a notification for all cell updates in excel.
My current code is something like this:
Private Sub Worksheet_Change(ByVal Target As Range)
...
End Sub
My problem is, that it only runs when a direct cell change happens. If I modify a cell, some other cells might change if their values relies on the modified cell.
Is there a way to detect these changes too? I would like to avoid the mirror copy method.
The following code will allow you to access all cells containing formulae which depend upon Target.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cell As Range
...
On Error Resume Next
For Each cell In Target.Dependents
' Do something
Next cell
On Error GoTo 0
...
End Sub
The On Error Resume Next statement is necessary because the loop will throw an error if there are no dependent cells.
You may also want to call Application.Calculate before that For Each loop in order to force re-calculation of those cells.
Kindly I need help after trying for hours myself.
I have this code to run a code base on a cell value change, but works only if I type myself the change.
I need to be automatic with the function I have inside the cell, but I can get it right.
This is the code I have now that works well manually:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = "$A$1" Then
Application.EnableEvents = False
Range("D10").Select
Selection.ClearContents
Application.EnableEvents = True
End If
End Sub
Anything that I should add to make it automatic with the formula inside?
This is a tricky one since there is no built in worksheet event that triggers when a particular cell has a value change due to a formula. There is, however, a Worksheet.Calculate event that could be used.
First we make a global string variable. This is a variable that is declared outside of a subroutine or function. It will hold it's value between executions of subroutines and functions. So we will declare it, and then set it to the value of A1 when A1 is changed.
Dim lastValue As String
Private Sub Worksheet_Calculate()
If Range("A1").Value <> lastValue Then
lastValue = Range("A1").Value
Range("D10").ClearContents
End If
End Sub
lastValue here is our Global that will hold the last known value of A1. When worksheet.calculate is triggered it will compare that value against A1 to see if it's changed, if it is then it executes your code to clear the contents of D1
Instead of a Global you could also just stick that last known value of A1 into a Cell somewhere too. Then do you comparison to that. The advantage of using a cell over a global variable, is that the cell value will hold it's value even if you close and reopen the sheet. So, depending on your needs, it may be a better option:
Private Sub Worksheet_Calculate()
lastValue = Range("Z10").value
If Range("A1").Value <> lastValue Then
Range("Z10").value = Range("A1").Value
Range("D10").ClearContents
End If
End Sub
Where Range Z10 is the spot that holds the last known value.
Lastly I reduced your code to clear contents of D10 to a single line. Anytime you see Something.Select and then in the next line see Selection.DoSomething you can just get rid of that Select/Selection bit. Selecting a cell is generally something that only a human needs to do to interact with the sheet. VBA can do whatever it likes to cells without have to Select them.
thanks in advance for any clarity you can offer.
In an Excel Workbook with many modules and worksheets, at the bottom of the VBA code for SHEET2, there is this Subroutine:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim TargetCells As Range
Set TargetCells = Range("B1000:B1029")
If Not Application.Intersect(TargetCells, Range(Target.Address)) Is Nothing Then
Call SpecificSubRoutine
End If
End Sub
My understanding of this code is that it watches the entire sheet for ANY changes. If ANYTHING is changed, anywhere on the sheet, it runs the If statement. The If statement fails in the event that any of the changes made to the sheet take place outside of the specified TargetCells range, but this Sub still tries to validate the If statement EVERY time ANYTHING is changed on the sheet.
Now, you might be able to guess that my problem is some stack overflow. (Run-time error '28': Out of Stack Space)
Whenever the Worksheet_Change Sub runs, if the changes to the sheet were made inside of the TargetCells range, it calls SpecificSubRoutine which populates cells, which triggers the Worksheet_Change Sub for every time SpecificSubRoutine populates ANY cell. (SpecificSubRoutine also calls different modules, which of course populate cells, which of course trigger the Worksheet_Change Sub)
Not so good.
Also, most of the subroutines throughout the application are wrapped in Application.ScreenUpdating = False / Application.ScreenUpdating = True, which I mistakenly thought would limit the number of times Worksheet_Change is called to once, immediately after Application.ScreenUpdating = True runs.
NOTE OF IMPORTANCE: Neither SpecificSubRoutine nor any of the Subroutines called by it populate cells in the TargetCells range. I'm not quite that dim...
Here are my questions:
Is there a way to narrow the scope of what triggers the Worksheet_Change Sub, so that only changes in the TargetCells range triggers it? (instead of changes anywhere in the sheet)
Is there a way to do what I mistakenly thought that Application.ScreenUpdating would do? (make changes to the sheet all in one bulk update, as opposed to triggering a change with nearly every step)
Also, as an extra curiosity, is there a way to have Worksheet_Change watch 2 specific ranges (instead of the whole sheet?) Knowing how to do this would be paramount, and would likely solve all of the problems on this sheet.
My intuition is to add an End to the last part of SpecificSubRoutine, or to the end of any/all of the Subroutines called by it, but I'm just not sure this will circumvent the looping through Worksheet_Change multiple times, since Application.ScreenUpdating doesn't bulk update like I thought.
Ideas?
Part 1: No - the event handler responds to all changes on the sheet: any filtering in how you respond to that change must occur in the handler itself.
Part 2: answered by #simoco
Part 3 (and incorporating simoco's suggestion):
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents=False
If Not Application.Intersect(Me.Range("B1000:B1029"), Target) Is Nothing Then
Call SpecificSubRoutine
End If
If Not Application.Intersect(Me.Range("D1000:D1029"), Target) Is Nothing Then
Call SomeOtherSpecificSubRoutine
End If
Application.EnableEvents=True
End Sub
I have a worksheet with many dependant dropdowns that are liable to having invalid data if the initial drop down is altered. I would like a simple auto-macro that would automatically run the "circle invalid data" command every time a cell change within a specified range (D8:T800) is detected.
It sounds fairly straightforward but I am not sure how to do this.
Question - as this macro will run every single time a cell is amended would this macro slow down the worksheet?
EDIT:
Also: as this might be slow,is there a way we can run this command over a selected range?
Your thoughts thanks.
Try this
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.Range("D8:T800")) Is Nothing Then
Me.CircleInvalid
End If
End Sub
Note that CircleInvalid applies to the whole sheet, so while this code only triggers when a cell inside D8:T800 changes, all invalid cells on the sheet will be circled
Try placing this code inside your Worksheet:
Private Sub Worksheet_Change(ByVal Target As Range)
' Check target range has changed
If (Not Intersect(Target, Range("D8:T800")) Is Nothing) Then
' Prevent recusrive looping
Application.EnableEvents = False
' Refresh validation circles
Target.Worksheet.CircleInvalid
Application.EnableEvents = True
End If
End Sub
Note that this will NOT work if the values in those cells change due to a calculation from outside the specified range.
Also, the CircleInvalid method applies to the whole worksheet.
You could try editing the code in the conditional to 'do something' if the Target is validated — this would result in you changing the format of invalid cells instead of having the red circles around them.
**PSEUDO-CODE**
For each cell in Target.Range
cell.colour = bright red
Next cell