I have a database which auto refreshes and updates the table from an external source every 15 minutes. I tried the following code which updates the PivotTable every time the source data is edit/added/deleted:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Worksheets("PIVOT TABLE WORKSHEET").PivotTables("PIVOT TABLE NAME").RefreshTable
End Sub
When i manually edit the source data, the PivotTables refresh accordingly. However, when the source data is updated automatically the PivotTables remain unchanged. Is there a way to make the Pivot tables refresh together with the database without the need of a user input?
You'll have better results if you use the Worksheet_Change event instead of the Worksheet_SelectionChange event, so that the procedure runs when data changes, not when you select a cell with the mouse or keyboard.
Worksheet_Change vs. Worksheet_SelectionChange events
Worksheet_SelectionChange fires when the selection changes on a worksheet.
For example, when the user clicks on a cell, or pushes an arrow key.
Worksheet_Change fires when cells on the worksheet are changed, either by the user or by an external link.
Note: Worksheet_Change does **not** occur when cells change during a re-calculation; use theCalculate` event to trap a sheet re-calculation.)
Depending on how the data is laid out in your worksheet(s), you may want to limit the execution of this procedure by checking which cell(s) were changed, which is easiest overall by comparing the event procedure's Target parameter to a specific cell or cell-range, using the Intersect function.
Caution: Beware of infinity!
When using code that changes cells within the area being "watched" by the Worksheet_Change event procedure, you risk entering into an infinite loop, since the change fires the event again, which changes cells again, etc.
(Click image to enlarge.)
There are several ways this could be avoided. This most common is to temporarily disable events with the Application.EnableEvents property while the Change event does what it needs to do. (Don't forget to re-enable events at the end of the procedure... see example below.)
Example:
Here's an untested example using all these points:
Private Sub Worksheet_Change(ByVal Target As Range)
Const cellsToWatch = "A1:D4"
With Worksheets("PIVOT TABLE WORKSHEET")
'exit the procedure if at least part of the changed cells were not within `A1:D4`
If Application.Intersect(.Range(cellsToWatch), Target) Is Nothing Then
'the change wasn't within `cellsToWatch`
Exit Sub
End If
Application.EnableEvents = False 'disable execution of this or other events
'----------Run your code here:--------------
.Calculate
.PivotTables("PIVOT TABLE NAME").RefreshTable
'-------------------------------------------
Application.EnableEvents = True 're-enable events
End With
End Sub
More Information:
MSDN : Worksheet_Change event (Excel)
MSDN : Worksheet_SelectionChange event (Excel)
MSDN : Application.Intersect method (Excel/VBA)
Office Support : Intercept function (Excel/Worksheet)
Stack Overflow : Stop Excel from firing Worksheet_Change before _BeforeSave?
MSDN : Application.EnableEvents property (Excel)
Related
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'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.
I have an Excel ListBox (not ActiveX as these are causing display issues) with an Excel (dialog menu-driven) macro that outputs its value to a named range cell on a different sheet to the Listbox. In that sheet's code I have the below
Private Sub Worksheet_Change(ByVal Target As Range)
Debug.Print "ping"
End Sub
The macro event does not trigger when I click on the Listbox (therefore updating the named range cell value). I have verified that the macro executes when I directly update that sheet.
I assume the form control macro is circumnavigating the sheet event trigger. Am I right? Does anybody know an efficient workaround for this? I am stumped.
Thanks Kindly
You can assign a macro to the ListBox as ListBox1_Change event (right click › assign macro) which will be executed on change of the ListBox value instead of Worksheet_Change then.
Probably that is why the Worksheet_Change is not triggered anymore when using the ListBox to change the cell value.
I have excel sheet, where I have bunch of data and some excel filter and sort buttons. Is there possibility to detect when sort function was executed and run code after?
I tried worksheet_calculate, but there is issue, that this event is firing not only on sort. Or is here possibility to determine that sort was performed in worksheet_calculate event?
Control the sort rather than have Excel try to detect the sort.Instead of allowing the user to manually perform sorts from the Ribbon, provide a button and have the button macro perform the sort and any associated actions afterwards.
A sort action changes the selection of its filter range. You can capture the sort event quite simply by utilizing the Worksheet_SelectionChange event. You must apply the Application.Intersect method the same way you would for a standard Worksheet_Change event.
The range you are testing against the selection target must be the filter range EXCLUDING the header row.
When you sort one of the columns within the filter range via the header controls, the Target.Value will capture an array including the header row values.
You need two lines of code at this point to help detect the sort action. Please see basic skeleton below:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim filterRangeNoHeaders As Range
Set filterRangeNoHeaders = Range("A2:A11")
If VarType(Target.Value) <> 8204 Then Exit Sub
If Target(1, 1) <> "FirstHeaderTitle" Then Exit Sub
If Not Application.Intersect(filterRangeNoHeaders, Target) _
Is Nothing Then
'Code to execute after sort is detected
End If
End Sub
How can I capture the event in Excel when a user clicks on a cell. I want to be able to use this event to trigger some code to count how many times the user clicks on several different cells in a column.
Check out the Worksheet_SelectionChange event. In that event you could use Intersect() with named ranges to figure out if a specific range were clicked.
Here's some code that might help you get started.
Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)
If Not Intersect(Target, Range("SomeNamedRange")) Is Nothing Then
'Your counting code
End If
End Sub
Use the Worksheet.SelectionChange event to trap this.
Worksheet SelectionChange event would do it. Note that this fires every time user clicks a new cell.