【问题标题】:VBA to connect slicers (looking for improvements to code)VBA 连接切片器(寻找代码改进)
【发布时间】:2017-01-28 16:39:58
【问题描述】:

我终于找到了一个代码,可以在数据透视表更新时将切片器与不同的缓存连接起来。基本上,当 slicer1 的值发生变化时,它会更改 slicer2 以匹配 slicer1 从而更新连接到第二个 slicer 的任何数据透视表。

我已添加 .Application.ScreenUpdating.Application.EnableEvents 以尝试加速宏,但它仍然滞后并导致 Excel 无响应。

是否有更直接的编码方式,或者这里是否有任何潜在的不稳定行导致 Excel 烧毁它的大脑?

Private Sub Worksheet_PivotTableUpdate _
    (ByVal Target As PivotTable)
Dim wb As Workbook
Dim scShort As SlicerCache
Dim scLong As SlicerCache
Dim siShort As SlicerItem
Dim siLong As SlicerItem

Application.ScreenUpdating = False
Application.EnableEvents = False
On Error GoTo errHandler
Application.ScreenUpdating = False
Application.EnableEvents = False

Set wb = ThisWorkbook
Set scShort = wb.SlicerCaches("Slicer_Department")
Set scLong = wb.SlicerCaches("Slicer_Department2")

scLong.ClearManualFilter

For Each siLong In scLong.VisibleSlicerItems
    Set siLong = scLong.SlicerItems(siLong.Name)
    Set siShort = Nothing
    On Error Resume Next
    Set siShort = scShort.SlicerItems(siLong.Name)
    On Error GoTo errHandler
    If Not siShort Is Nothing Then
        If siShort.Selected = True Then
            siLong.Selected = True
        ElseIf siShort.Selected = False Then
            siLong.Selected = False
        End If
    Else
        siLong.Selected = False
    End If
Next siLong

exitHandler:
    Application.ScreenUpdating = True
    Application.EnableEvents = True
    Exit Sub

errHandler:
    MsgBox "Could not update pivot table"
    Resume exitHandler
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub

Contextures找到的原始代码

一如既往地感谢您的任何建议。

link to original inquiry:

【问题讨论】:

  • 你循环了多少个切片器项目?
  • 它可能会很慢。在 slicercache 中使用 sliceritems 进行监控会导致对其连接的 pivotcache 进行过滤,这需要处理。因此,每次将sliceritem.selected 翻转到truefalse 时,pivotcache 都会针对连接的数据透视表进行过滤并进行 excel 爬网。我猜..理论上你可以清空连接的数据透视缓存(暂时移动数据但不移动标题并刷新),然后运行此代码通过切换sliceritems.Selected属性过滤空,然后将数据折回并刷新一次可旋转...?
  • @Kyle Alot 可能还会有更多。我想知道设置“slicer2”的值/选择以匹配隐藏单元格的值/选择是否是更好/更快的解决方案?例如让A1 =主数据透视表的过滤值,然后将“切片器2”选择设置为等于单元格A1的选择?我不确定如何破译这个,到目前为止还没有出现任何功能编码。
  • 每个切片器中有多少项会被选中?只有1个?还是希望用户能够进行多项选择?
  • 当您说“很多,可能还会更多”时,您能说得更具体些吗?您需要同步多少个数据透视表?每个项目中有多少个 PivotItem?

标签: excel pivot-table slicers vba


【解决方案1】:

如果您只希望用户一次只选择一个项目,您可以使用以下技巧快速完成此操作,该技巧利用 PageFields 的一个怪癖。这是一个示例,其中我同步了位于不同缓存中的三个不同数据透视表。

  1. 为每个主数据透视表设置一个从数据透视表 看不见的地方,把感兴趣的领域放在每个 它们作为一个 PageField,像这样:

  2. 确保取消选中每个从属数据透视表的“选择多个项目”复选框
  3. 为每个从属设备添加一个切片器。同样,这些将是看不见的地方:
  4. 将每个切片器连接到您必须开始使用的实际数据透视表。 (即使用报告连接框将每个隐藏的切片器连接到它的可见对应数据透视表。

现在这就是聪明的 hack 的用武之地:我们将连接到 PivotTable1 Slave PivotTable 的 Slicer 移动到主工作表中,以便用户可以单击它。当他们使用它选择一个项目时,它会为该 PivotTable1 Slave PivotTable 生成一个 PivotTable_Update 事件,我们会密切关注该事件。然后我们将其他从数据透视表的 .PageField 设置为与 PivotTable1 从数据透视表的 .PageField 相匹配。然后更神奇的事情发生了:由于我们之前设置的隐藏切片器,这些从属 PageFields 中的单个选择被复制到主数据透视表中。不需要 VBA。不需要缓慢的迭代。只是闪电般的快速同步。

整个设置如下所示:

...即使您要过滤的字段在您的任何数据透视表中都不可见,这也将起作用:

这是实现此目的的代码:

Option Explicit

Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)

Dim pt As PivotTable
Dim pf As PivotField
Dim sCurrentPage As String
Dim vItem As Variant
Dim vArray As Variant

'########################
'# Change these to suit #
'########################

Const sField As String = "Name"
vArray = Array("PivotTable2 Slave", "PivotTable3 Slave")


If Target.Name = "PivotTable1 Slave" Then
    On Error GoTo errhandler
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
        .EnableEvents = False
    End With

    'Find out what item they just selected
    Set pf = Target.PivotFields(sField)
    With pf
        If .EnableMultiplePageItems Then
            .ClearAllFilters
            .EnableMultiplePageItems = False
            sCurrentPage = "(All)"
        Else:
            sCurrentPage = .CurrentPage
        End If
    End With

    'Change the other slave pivots to match. Slicers will pass on those settings
    For Each vItem In vArray
        Set pt = ActiveSheet.PivotTables(vItem)
        Set pf = pt.PivotFields(sField)
        With pf
            If .CurrentPage <> sCurrentPage Then
                .ClearAllFilters
                .CurrentPage = sCurrentPage
            End If
        End With
    Next vItem

errhandler:
    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
        .EnableEvents = True
    End With
End If

End Sub

其中有一些代码可确保用户一次不能在切片器中选择多个项目。

但如果您希望用户能够选择多个项怎么办?

如果您希望用户能够选择多个项目,事情就会变得更加复杂。对于初学者,您需要将每个数据透视表的 ManualUpdate 属性设置为 TRUE,以便它们不会在每次 PivotItems 更改时刷新。即便如此,如果其中有 20,000 个项目,仅同步一个数据透视表可能需要几分钟时间。我建议您阅读以下链接中的一篇很好的帖子,它显示了在迭代大量 PivotItems 时执行不同操作需要多长时间: http://dailydoseofexcel.com/archives/2013/11/14/filtering-pivots-based-on-external-ranges/

即便如此,您还有很多其他挑战需要克服,具体取决于您正在做什么。对于初学者来说,切片机似乎真的减慢了速度。阅读我在http://dailydoseofexcel.com/archives/2015/11/17/filtering-pivottables-with-vba-deselect-slicers-first/ 的帖子以了解更多信息。

我正处于发布商业插件的最后阶段,该插件可以闪电般快速地完成大量此类工作,但至少要一个月后才能发布。

【讨论】:

  • 嘿,非常感谢您的回复,我在答案上方添加了对您的 cmets 的附加回复。正如您将在上面阅读的那样,我不确定这是否对我有用。我试图弄清楚的另一种方法是,我是否可以将切片器 1 的选定项目发送到一个单元格,并使用该值来驱动为第二个缓存上的表选择切片器。非常感谢。
  • 是的,您可以将 Slicer1 的选定项目发送到一个单元格,但是您仍然面临将 Slicer2 同步到该项目的问题。这将要求您遍历 Slicer2 的 SlicerItems(或它连接到的数据透视表之一),这会让您回到最初的问题。阅读此链接,因为它解释了其中涉及的固有问题:dailydoseofexcel.com/archives/2013/11/14/…
  • 如果你在所有连接到 Slicer2 的枢轴中将 .ManualUpdate 设置为 true,那么事情会变得更快。但这仍然比我上面建议的方法复杂得多,即使用 Slave 枢轴来“收获” Slicer1 上的点击,然后通过 Slicer2 有效地将单个选择同步到其他枢轴
  • 我无法弄清楚如何调整它以允许同步两个不同的切片器类别。试过第二组从表,第二页字段,嗯。
  • Awill...两个不同的切片器类别名称是什么?您基本上需要复制顶部的注释和底部的 errhandler 之间的所有内容,然后更改以下位以反映第二个切片器和枢轴的名称: Const sField As String = "Name" vArray = Array("PivotTable2从属", "PivotTable3 从属") If Target.Name = "PivotTable1 Slave" Then...
【解决方案2】:

我不确定我做错了什么。我在下面发布了我的代码,我没有遇到任何错误,只是没有更新任何其他切片器/字段。在第一次测试时,部门切片器更新了所有表一次,但不会清除过滤器或允许其他选择,就月份切片器而言,我根本没有让它工作。我是否可能需要复制每个项目以便单独识别?如Dim sCurrentPage As StringDim sCurrentPage2 As String。非常感谢您在这方面的持续帮助,我以前在处理电子表格时从不希望周末来得如此糟糕。

Option Explicit

Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)

Dim pt As PivotTable
Dim pf As PivotField
Dim sCurrentPage As String
Dim vItem As Variant
Dim vArray As Variant
Dim sField As String

'########################
'# Change these to suit #
'########################

sField = "Department"
vArray = Array("PivotTable2 Slave", "PivotTable3 Slave")


If Target.Name = "PivotTable1 Slave" Then
    On Error GoTo errhandler
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
        .EnableEvents = False
    End With

    'Find out what item they just selected
    Set pf = Target.PivotFields(sField)
    With pf
        If .EnableMultiplePageItems Then
            .ClearAllFilters
            .EnableMultiplePageItems = False
            sCurrentPage = "(All)"
        Else:
            sCurrentPage = .CurrentPage
        End If
    End With

    'Change the other slave pivots to match. Slicers will pass on those settings
    For Each vItem In vArray
        Set pt = ActiveSheet.PivotTables(vItem)
        Set pf = pt.PivotFields(sField)
        With pf
            If .CurrentPage <> sCurrentPage Then
                .ClearAllFilters
                .CurrentPage = sCurrentPage
            End If
        End With
    Next vItem

'########################

sField = "Month"
vArray = Array("PivotTable2 Slave2", "PivotTable3 Slave2")


If Target.Name = "PivotTable1 Slave2" Then
    On Error GoTo errhandler
    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
        .EnableEvents = False
    End With

    'Find out what item they just selected
    Set pf = Target.PivotFields(sField)
    With pf
        If .EnableMultiplePageItems Then
            .ClearAllFilters
            .EnableMultiplePageItems = False
            sCurrentPage = "(All)"
        Else:
            sCurrentPage = .CurrentPage
        End If
    End With

    'Change the other slave pivots to match. Slicers will pass on those settings
    For Each vItem In vArray
        Set pt = ActiveSheet.PivotTables(vItem)
        Set pf = pt.PivotFields(sField)
        With pf
            If .CurrentPage <> sCurrentPage Then
                .ClearAllFilters
                .CurrentPage = sCurrentPage
            End If
        End With
    Next vItem

errhandler:
    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
        .EnableEvents = True
    End With
End If

End Sub

【讨论】:

  • Awill - 将您的电子表格通过 weir.jeff@gmail.com 发送给我,我会看一下,然后再发回这里。
  • 鉴于此答案已经解决了您的原始问题,您如何将其标记为已接受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-14
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 2016-03-27
  • 2011-05-01
相关资源
最近更新 更多