A similar unanswered question lies here: Excel Macro slicer onclick event
I have a ListObject and a Slicer on that ListObject. The slicer is called "Year". I'm able to trap the on click event with
Private Sub Year_Click()
doCalcsOnFilteredListObject
End Sub
Just right click on the slicer heading > Add Macro
Problem is that I want the trapped event to happen, after the filter selection has been applied. Right now, I trap the event, the filter is never applied, but the calc function runs fine on the (unaltered) listobject.
There are no events for ListObjects and Slicers. The Year_Click you have is an event of container object not of SlicerItem.
The workaround is creating a DUMMY worksheet that has SUBTOTAL Formula on A1 Cell and trap a SheetCalculate event on it. So that when you click on Slicer, it recalculates the formula on DUMMY!A1 after filtering.
Procedures:
Create a new sheet named "DUMMY" & put a formula in A1 cell: "=SUBTOTAL(109, Table1[YEAR])". (Adjust appropriately to your ListObject & Column names.)
Put this VBA procedure.
Private Sub Workbook_SheetCalculate(ByVal Sh As Object)
If Sh.Name = "DUMMY" Then
doCalcsOnFilteredListObject
End If
End Sub
Select criteria in Slicer.
This should trigger the desired event and call your custom procedure.
Be aware that Automatic Calculation must be turned on. If you want Manual Calculation, there is a technique using Workbook_Open that sets all sheets into Manual Calculation except the DUMMY sheet.
Related
I have a worksheet, and I want to run a macro when the active sheet is renamed (renamed to anything).
The reason for this is as follows:
I have a Pivot table that is filtered based on a cell (D1) value, using VBA.
(When the D1 is changed, the pivot table filter changes).
D1 is, in turn, determined (matched) by the sheet name, using a formula.
(I.e. if the sheet name is RG01, then D1 automatically changes RG01)
The problem is, when the sheet name is changed (and D1 changes with it) it does not trigger a change in the Pivot table filter. It's only when I edit D1 that the Pivot table filter changes. I.e. If I select D1 and re-enter the formula, the Pivot Table filter changes.
So, I'm thinking, I could write a macro that re-enters the formula in D1 whenever the sheet is renamed. I can do most of this by 'recording' a macro, but I don't know how to trigger the macro when the sheet is renamed.
By "re-enter" I mean clicking the cell (D1), clicking the formula bar, then pressing enter.
Apologies, I'm not proficient in VBA or excel so my terminology may be wrong. I'm so close to making my spreadsheet work and this is the final hurdle that I just cannot seem to get around.
Thank you so much is anticipation!
For a project where I wanted to capture sheet renaming I used a public variable for the active sheet name and with a Workbook_SheetCalculate I was capturing the change.
(Note that this worked for the active sheet renamed by hand and not programmaticaly renaming other sheets name from a macro. That would probably need a public array/dict with alll the sheet names stored on opening the workbook)
A sample code would be:
(ThisWorkbook):
Public LastSheet As String
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
LastSheet = ActiveSheet.Name
End Sub
Private Sub Workbook_SheetCalculate(ByVal Sh As Object)
If LastSheet <> ActiveSheet.Name Then
'... do something here
LastSheet = ActiveSheet.Name
End If
End Sub
The calculate sub would fire in every change in the active sheet but run the desired code only when the sheet name changes.
I have a table tbl1 with a list of names. When I select any row in the column "name", I would like to run a macro to filter another table tbl2. When I deselect that same row, I would like to run another macro to unfilter tbl2.
So far, I have gotten the filter on select part working, but I am stuck on how to get it to unfilter on deselect. FilterTableByName and UnfilterTableByName are both macros that will filter/unfilter tbl2.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Not Intersect(ActiveSheet.ListObjects("tbl1").ListColumns("name").Range, Target) Is Nothing Then
Call FilterTableByName(ActiveCell.Row)
End If
End Sub
An alternate solution that I thought of was to call unfilter and then filter macros on select, and then call unfilter when I leave the worksheet, but I was wondering if there was a cleaner way to unfilter instead of running it every time I click a different worksheet. Thanks
I am looking to detect any changes in an autofilter on a specific table, for the purpose of forcing a UDF that does some simple arithmetic on the table entries that are currently visible to update its result. Making the UDF volatile has had no impact so far, but it doesn't target the table directly either.
This solution (https://stackoverflow.com/a/15906275/4604845) does not work for me, probably because I have only manual calculation.
My a-little-too-dirty workaround is Workbook_SelectionChange, and while the UDF doesn't kill resource consumption this way, I'd rather avoid it in case the data grows larger. Also I have some users that are complete novices in terms of using computers, and I have trouble being confident that I can get all of them to understand that they need to click something else after updating the autofilter for the result to be correct.
Any ideas? I have tried Workbook_Change and Workbook_Calculate but none of them are triggered (or I can't figure out how to trigger them) by the autofilter changes.
Even if you have no other formulas on the worksheet, if you include a Subtotal() formula somewhere on the sheet referencing the table, the Subtotal() will recalculate every time the autofilter is changed.
You can use this to trigger a Calculate() event macro.
EDIT#1:
Say we have an AutoFilter set on column A of a sheet named data. Sheet data also contains many other formulas. If we use the Calculate() event in the data worksheet, we will get fires any time any of these formulas re-calculate.
We create a new worksheet called trigger. This new worksheet is comletely empty except for a single cell that contains:
=SUBTOTAL(3,data!A1:A20)
It is in the trigger worksheet that we place the Calculate() event macro.
Now if we are using the data worksheet, we can make arbitrary changes and perform various recalculation and nothing fires, but if we change the AutoFilter, the event macro on trigger will see the change and fire!
How to trigger Worksheet Calculation following AutoFilter changes while in Manual Calculation
As we know changes to the AutoFilter selection cannot be automatically detected, as these changes do not trigger any Workbook Event or Worksheet Event. Therefore, only option available is to have the user triggering worksheet calculations with an action i.e. Cell Selection Change, Right Click, Double Click, etc; or just by pressing [F9]; which is the preferable action as there is nothing else involved and it's the way it's designed to work.
Nevertheless, at the user request, I'm providing this VBA code that although needs to be initiated by user's action, this action can be done immediately after the AutoFilter change is selected, just by Double Clicking.
The DoubleClick can be unrestricted (double clicking any cell in the worksheet) by using this code:
Private Sub Worksheet_BeforeDoubleClick(ByVal rTrg As Range, blCancel As Boolean)
rTrg.Worksheet.Calculate
End Sub
or setting up to three types of restrictions:
Any cell of the Table
The Header of the Table
The Body of the Table
Use this code to restrict the DoubleClick area:
Currently the code is set to restriction type 1, use variable bRType to change it to the preferred type. This code assumed the name of the Table is Table1 (change as required)
Private Sub Worksheet_BeforeDoubleClick(ByVal rTrg As Range, blCancel As Boolean)
Dim ObjLst As ListObject, rTbl As Range, bRType As Byte
Rem Set Restriction Type
Rem 1: DoubleCliking any cell of the Table - Default
Rem 2: DoubleCliking any cell of the Table Header
Rem 3: DoubleCliking any cell of the Table Body
bRType = 1
With rTrg
Set ObjLst = .Worksheet.ListObjects("Table1")
Select Case bRType
Case 2: Set rTbl = ObjLst.HeaderRowRange
Case 3: Set rTbl = ObjLst.DataBodyRange
Case Else: Set rTbl = ObjLst.Range
End Select
If Not (Intersect(.Cells, rTbl) Is Nothing) Then
.Worksheet.Calculate
blCancel = True
End If
End With
End Sub
Both procedures are Worksheet Events, therefore ensure that the one that you decide to implement goes into the module of the worksheet holding the Table. (do not change the name of the procedures)
I'm a little new to Excel VBA. I've currently designed VBA code to produce a Vlookup that populates data in a column(say column Y) in my datasheet based on ref data in another sheet, and a filled value in another column (column X) of the same sheet. This I'm performing on the Workbook_Open event.
I need to, however, also be able to update column Y's value when column X's value is changed in a particular row. Also, if an additional row is added, I need to be able to provide a Y value for that too. However, I can't seem to find an appropriate event for the same, barring the selection changed event at Worksheet level, which is triggered when u change which cell you've selected.
Try the worksheet change event... To ensure something happened in Column X, you would write somethign like this:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("X:X")) Is Nothing Then
MsgBox ("Hi")
End If
End Sub
Hope this helps
I have a set of Pivot tables/charts automatically created from VBA code with custom formatting.
When I change the selection of data to be displayed from the drop down list in the chart, the custom formatting reverts back to the chart type's default display. The underlying chart data is not changed, only what's displayed on the chart. What do I have to do to retain that custom formatting everytime I change the pivot item selection in a row field?
Edit 1: The underlying data for the pivot table does not change. However, everytime I change a filter on a row, column or page field, the updated pivot chart loses the original format set by the VBA code.
Edit 2: This only pertains to Excel versions older than Excel 2007.
What it sounds like to me is that the VBA code generates the pivot table/chart and then you are trying to tweak it afterwards. Unfortunately with VBA, when you update the pivot table/chart, all your custom formatting is lost. Excel is basically creating a new one each time as well.
If you did the formatting by hand in Excel, I think Excel keeps track of that and will keep your formatting as you change the data. The example I can think of is if you accidentally delete a sheet you an Undo it, however if you delete a sheet in VBA there's no possible way to Undo.
I would try this as a solution.
Create two procedures: one that creates a PivotTable from scratch when given data, and the other that formats a pivot table when given the range of a pivot table. The code could look something like this
Sub GeneratePivotTable(rng as Range, var1 as Variant, var2 as Variant)
' Code here that makes your Pivot Table
' pass whatever you need to get the job done
End Sub
Sub FormatPivotTable(rng as Range, var1 as Variant, var2 as Variant)
' Code here to format pivot table given range and other information
' You might even be able to just directly pass a PivotTable object :D
End Sub
Then all you would have to do next to make it functional like your current code is create a wrapper function that just calls both.
Sub GenerateAndFormatPivotTable(rng as Range, var1 as Variant, var2 as Variant)
Call GeneratePivotTable(rng, var1, var2)
' Maybe some processing here to set up the next call
Call FormatPivotTable(rng, var1, var2)
End Sub
If you wanted to pass the PivotTable as an object you could do something neat like....
Function GeneratePivotTable(variables as Variant) as PivotTable
' Generate your pivot table and return it
GeneratePivotTable = myPivotTableThatIMade
End Function
Sub FormatPivotTable(aPivotTableThatYouMake as PivotTable)
' Code that formats your PivotTable
End Sub
Sub GenerateAndFormatPivotTable(rng as Range, var1 as Variant, var2 as Variant
Call FormatPivotTable(GeneratePivotTable(variables as Variant)
End Sub
You do all this so if you make a table, then have to tweak it, you can use that FormatPivotTable to format the updated table.
For extra madness, have the sheet that has the PivotTable fire it's Worksheet.Change or Worksheet.Activate event to search for a PivotTable and call your formatting function :D