I want to add some VBA code when the value in a cell changes.
I've already tried Worksheet_Change() as described at Contextures however, this won't work: it only fires when the user changes the value. I want to fire it whenever the value changes, i.e. whenever the spreadsheet recalculates.
Any ideas?
Private Sub Worksheet_Calculate()
MsgBox "Something recalculated", vbOKOnly, "Testing Actions"
End Sub
Related
I'm sure to people this is going to seem like a simple question but I can't find a way to do it and google is not return examples of the issue I'm having. I'm looking to say that if a cell = value from a dropdown list and another cell value is blank then it should show a message box. What I keep finding is how to call other macros on drop list change.
The code I have is simple and looks like this:
Sub failuremsg()
If H10 = "Failed" And J10 = "" Then
MsgBox "Failure message is missing", vbOKCancel
End If
End Sub
If I change and test with just J10 in then it brings up the message box. If I test with just H10, which is the dropdown list cell, then it does nothing which indicates to me that there is something I'm missing in the code to tell it that H10 is a dropdown list and if it equals the value I want then to run.
Is anyone able to help or point to an article that could assist with this please as I'm stuck.
Thanks very much for your time.
In this code H10 and J10 are considered to be variables which are empty! They are no cell values.
If you mean them to be cell values you need to fully reference them with workbook, worksheet and range like:
ThisWorkbook.Worksheets("Sheet1").Range("H10").Value
To avoid such issues I recommend always to activate Option Explicit: In the VBA editor go to Tools › Options › Require Variable Declaration. Then you get notified if you use variables that are not declared and you won't end up with something that is enirely different from what you thought it actually is.
Option Explicit
Public Sub failuremsg()
If ThisWorkbook.Worksheets("Sheet1").Range("H10").Value = "Failed" And ThisWorkbook.Worksheets("Sheet1").Range("J10").Value = vbNullString Then
MsgBox "Failure message is missing", vbOKOnly 'use OK only if there is no choice for the user anyway!
End If
End Sub
This macro works as intended, from a button on the Batch Input sheet:
Sub BatchTriggerOFF()
Sheets("Batch Input").Unprotect
Sheets("Batch Input").Range("G3:J3").Value = "Off"
Sheets("SQL LOGIC").Calculate
Sheets("Batch Input").Range("A12").Select
Sheets("Batch Input").Shapes.Range(Array("Group 12")).ZOrder msoSendToBack
Sheets("Batch Input").Protect
End Sub
However, when BatchTriggerOFF is called from a different sheet in the same workbook, the macro neither changes the Range("G3:J3").Value nor Shapes.Range(Array("Group 12")).ZOrder msoSendToBack. There is no error message.
If Sheets("SQL LOGIC").Range("B1") = "On" Then Call BatchTriggerOFF
I've tried unprotecting the Batch Input sheet beforehand, messing with Sheets("Batch Input").Activate, Sheets("Batch Input").Select, and even tried pasting the BatchTriggerOFF line by line VBA directly into the second macro, to no avail.
What is causing BatchTriggerOFF to seemingly not run when called from the second macro/sheet?
[...] something is inherently wrong with the second code I've provided, likely not actively running when the value in Range("B1") is changed?
Exactly. A procedure that's in a standard module needs something, somewhere to invoke it. Could be a shape or button on the worksheet, could be other VBA code, but something needs to invoke it somehow.
No procedure is going to just know to run when Range("B1") is changed on Sheets("SQL LOGIC"): you need to have code that's "triggered" when a cell is changed on that sheet.
The way to do this, is to handle the worksheet module's Change event. Find your "SQL LOGIC" sheet in the VBE's Project Explorer (Ctrl+R), double-click it. In the code-behind module for that specific worksheet, select Worksheet from the left-side dropdown at the top of the code pane; the right-side dropdown should say SelectionChange, and the VBE should have added a private procedure that looks like this:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
Select Change from the right-side dropdown; the VBE creates a private procedure that looks like this:
Private Sub Worksheet_Change(ByVal Target As Range)
End Sub
Now delete the SelectionChange handler, you don't need it unless you need to track cells that the user has selected. Since we want to track cells that have changed, we'll use the Change worksheet event. This procedure will be invoked whenever the user or your code changes anything on that sheet.
Since we only care to run code when a specific cell is changed, we need a condition here, involving the Target parameter. Using the Application.Intersect function, we can get a Range object reference that's Nothing if the two specified ranges don't intersect; we can use this information to bail out if it's not B1 that changed:
If Application.Intersect(Me.Range("B1"), Target) Is Nothing Then Exit Sub
Any code written after that condition inside the Worksheet.Change event handler procedure, will only run after the value of cell B1 was modified - either by the user typing in a value, or by any other code writing to that cell (you need to toggle Application.EnableEvents off if you have to prevent firing that event when it's code doing the changes and you don't want the handler to run).
Now, it looks like cell B1 isn't going to change, rather, it looks like it contains a formula whose result might change after making changes to the "Batch Input" sheet.
If that's the case, then the Change event will not be fired when B1 recalculates and now evaluates to a new value, because the cell didn't change, only its result.
If that's your scenario, then you want to handle the Calculate worksheet event, and have that be your trigger:
Private Sub Worksheet_Calculate()
If Me.Range("B1").Value = "On" Then BatchTriggerOFF
End Sub
If you need your sub to be called from any (sheet) module, move it in a module! The function/sub in the sheet module cannot be called without specifying the module name where it belongs, like you will be able to do in a module.
I receive every week a file that has always the same structure and format and what I want to do is to get a message when double clicking in some the cells of one of the columns.
I have the code and it works but I have to paste everytime in the worksheet once I open it. I want make this code "generic" so I can use it automatically everytime I open one of these workbooks without having to copy every time or do anything rather than the double clicking to get the message.
Private Sub Worksheet_BeforeDoubleClick(ByVal target As Range, cancel As Boolean)
If Not Application.Intersect(target, myrange) Is Nothing Then
cancel = True
MsgBox "some message"
End If
End Sub
Some comments.. the sheet i need to work with it's always called the same and the column I need to work with is always the same too. The only change is the number of rows it contains.
After some research I don't know if I should do this in a class module or as an addi-in. I'm a begginer in VBA so this is out of my scope...yet.
Thanks!
I have created a Command button and written a small code using if condition to match my criteria. Its working fine if their is any value in the cell/range, its doing according to code "asking to enter the data" and if their is any value "saying data is already enter" and disabling the button(what exactly i wanted).
But, when i am re-entering the data/value into those cell, it's not re-enabling the button back automatically. I have to manually have to go to properties to enable it, which i don't want to do everytime.
Below is my code"
Private Sub RESET_Click()
If Range("A10").Value = "" Then
Reset.Enabled = False
MsgBox "Data has already updated for this period"
Else
Reset.Enabled = True
MsgBox "Please, enter the data"
End If
End Sub
It's not re-enabling the button even after i have listed True in else condition.
Please, also let me know if their is way. So, i can reset/re-enable this button on 1st of every month automatically using VBA.
I would appreciate your response.
Thanks
It seems that your code is triggered by the button press. This way, once the first condition of the if statement is met, the button is disabled and won't run its code anymore.
Maybe what you want is to re-eanable the button when cell changing. So put this code on the worksheet after setting your sub to public:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Target.Worksheet.Range("A10")) Is Nothing Then call RESET_click
End Sub
EDIT:
Maybe you also have to set the button object inside your main sub:
Set Reset = yourworksheet.Buttons("yourbuttonname")
I would also recomend not to use Reset as name inside VBA, since it is already a statement, and may cause confusion.
I'd like to know on how to code a userform (VBA Excel) with automatically updating itself when the cell values has changed.
I have produced a button that will show the userform with labels and text boxes. But whenever i click it yes it shows up but i need to click the userform in order for me to see the values.
Need help.
Thank you in advance,
Tramyer
The Worksheet.Change event is fired everytime you change the contents of a cell on a given worksheet.
You can create an event handler in the worksheet module (usually labeled Sheet1, Sheet2 etc. in the VBA editor) that is called every time the event is fired:
Private Sub Worksheet_Change(ByVal Target As Range)
Debug.Print Target.Address
End Sub
This example just outputs the address of the cell that was changed, but you can adapt this to update your userform with the changed values instead.