【问题标题】:unable to get the visible property of the pivotitem class无法获取数据透视项目类的可见属性
【发布时间】:2015-12-30 10:46:10
【问题描述】:

我有两套代码。出于某种原因,在第一个错误,而在第二个错误

1:

Dim pi As PivotItem
Dim pf As PivotField

Set pf = Sheets("Afname per school").PivotTables("Draaitabel3").PivotFields("school")

For Each pi In pf.PivotItems
    If pi = "(leeg)" Then
        pi.Visible = False
    Else
        pi.Visible = True 'ERROR HERE
    End If
Next pi

2:

Dim pi As PivotItem
Dim pf As PivotField

Set pf = Sheets("Afname per school").PivotTables("Draaitabel3").PivotFields("naam locatie")

For Each pi In pf.PivotItems
    If InStr(pi, "BSO") Then
        pi.Visible = True
    Else
        pi.Visible = False
    End If
Next pi

我收到错误:“无法获取数据透视项目类的可见属性”

我读到我应该解决这个问题:

这是由于 Pivot 表使用缓存的数据透视项目而不是 当前的。确保桌子没有保留任何旧物品。到 这样做,右键单击您的数据透视表,单击数据选项卡并设置 “每个字段保留的项目数”为“无”。这样做的代码 VBA 是:

将 pt 调暗为数据透视表

pt.PivotCache.MissingItemsLimit = xlMissingItemsNone

我尝试通过两种方式添加这行代码:

Dim pi As PivotItem
Dim pf As PivotField

Set pf = Sheets("Afname per school").PivotTables("Draaitabel3").PivotFields("school")

pt.PivotCache.MissingItemsLimit = xlMissingItemsNone  '1st TRY

For Each pi In pf.PivotItems
    pt.PivotCache.MissingItemsLimit = xlMissingItemsNone   '2nd TRY
    If pi = "(leeg)" Then
        pi.Visible = False
    Else
        pi.Visible = True
    End If
Next pi

这似乎没有解决我的问题。

【问题讨论】:

  • 在cmets中开始解释,但是太长了,开始一个答案! ;) 只是一个简单的问题:您的行/列字段中是否有多个字段?
  • 感谢您的帮助!事实上,我没有。有一个行字段和一个列字段。如果我想添加一个,它会改变很多吗?
  • 顺便说一句。如果我的数据透视字段是报表过滤器,这有关系吗?
  • 显然不是,它似乎以同样的方式工作。但是,对于其他过滤器,某些 PivotItem 可能无法显示,因为它们与您数据集中的现有行不对应。让我知道我的回答是否对您有所帮助

标签: vba excel pivot-table pivotitem


【解决方案1】:

1。您的行/列字段中是否有多个字段?

因为问题可能来自于此。

PivotField 中的所有 PivotItem 并不总是显示/可显示,因为它们位于第二级,具体取决于第一级。 为避免因错误而导致代码中断,您必须使用 错误处理程序

只有从第一级找到的具有相应 PivotItem 的 PivotItem 是可显示的(即,您无法显示数据中未发生的情况)。

例如,您不能在第二级显示 PivotItem“汽车”

当第 1 级 PivotItem 为“飞行交通工具”时。


2。刷新数据透视缓存

话虽如此,您可以在使用设置 MissingItemsLimit 后立即刷新数据透视缓存(检查您是否已将 Pt 定义为您的数据透视表)以确保您拥有最新数据:

Set Pt = Sheets("Afname per school").PivotTables("Draaitabel3")
Set pf = Pt.PivotFields("school")
Pt.PivotCache.MissingItemsLimit = xlMissingItemsNone
Pt.PivotCache.Refresh

3。代码逻辑

之后再看你的代码,我有点困惑,因为你所做的是隐藏一个通过他的名字找到的特定 PivotItem,但你也尝试显示所有其他 PivotItem!

我认为这是这里的主要问题,我会建议一个带有少量参数和错误处理的例程,如下所示:

Sub Hide_PivotItem(PivotTable_Object As PivotTable, _
                    PivotField_Name As String, _
                    ByVal PivotItem_Name As String, _
                    ByVal UnHide_All As Boolean)

    Dim Pt As PivotTable, _
        Pi As PivotItem, _
        Pf As PivotField
    
    Set Pt = PivotTable_Object
    Set Pf = Pt.PivotFields(PivotField_Name)
    
    Pt.PivotCache.MissingItemsLimit = xlMissingItemsNone
    Pt.PivotCache.Refresh
    
    If UnHide_All Then
        On Error Resume Next
        For Each Pi In Pf.PivotItems
            Pi.Visible = True
        Next Pi
        On Error GoTo 0
    Else
        'Don't unhide other items
    End If

    For Each Pi In Pf.PivotItems
        If Pi.Name <> PivotItem_Name Then
        Else
            Pi.Visible = False
        End If
    Next Pi

End Sub

【讨论】:

  • 我正在尝试。可能需要一些时间。
  • 嗯,我似乎无法正常工作。几个问题: 1. 在我的示例中,我使用什么作为“PivotItem_name”? 2. 我觉得在你的代码中,一开始你试图取消隐藏所有内容,然后你又试图隐藏所有内容。
  • 很高兴我能帮上忙! ;)
  • R3uK:你的回答有些问题。
  • 哎呀,在我完成之前按了输入。 R3uK:我不明白您如何评论“PivotField 中的所有 PivotItems 并不总是显示/可显示,因为它们处于第二级,取决于第一级。”以任何方式与问题相关。无论它们是否可显示,它们都将在 PivotItems 集合中,与此错误发生无关。您刷新数据透视表以确保捕获最新数据的建议不是操作要求的,也与错误无关。
【解决方案2】:

Grafit:您发布的两个代码 sn-ps 做了非常不同的事情。第一个使除值“(leeg)”之外的所有内容都可见。第二个使任何带有“BSO”的项目可见,并隐藏其他所有项目。两段代码都有问题。

关于您的第一个代码 sn-p,如果您想显示除名为“(leeg)”的项目之外的所有项目,则无需遍历 PivotItems 集合(在大型 Pivot 上确实很慢) .相反,只需这样做:

pf.ClearAllFilters pf.PivotItems("leeg").visible = false

关于您的第二段代码,是的,错误可能是由 MissingItemsLimit 问题引起的,但如果代码尝试隐藏 PivotItem 而在循环期间当前没有其他 PivotItem 可见,也会发生此错误。例如,如果您对数据透视表进行了过滤,例如“Aardvark”,那么由于“Aardvark”中没有“BSO”,代码将尝试隐藏它,然后会出错,因为在至少一个 PiovtItem 必须始终保持可见。

因此,您要做的就是在循环之前添加一行 ,使 PivotItems 集合中的 last 项可见,这样您几乎可以保证一个项目将一直可见到循环结束。

(当然,如果“BSO”没有出现在任何 PivotItems 中,那么当您去处理最后一个项目时,您仍然会收到错误消息)。

此外,每当您遍历 PivotITems 集合时,您通常希望将 PT.ManualUpdate 设置为 True,这样数据透视表就不会在每个项目被隐藏/取消隐藏后尝试更新数据透视表中的总计。然后在例程结束时再次将 PT.ManualUpdate 设置为 False,然后告诉 Excel “我完成了……您现在可以更新这些数据透视表总计。”这通常会在您的例行程序速度方面产生惊人的差异。在大型枢轴上,您将节省大量时间。

我在http://dailydoseofexcel.com/archives/2013/11/14/filtering-pivots-based-on-external-ranges/ 写了一篇深入讨论这些内容的文章,建议您查看。

--edit-- 这是一个清除数据透视表以便只显示一个项目的例程:

Sub FilterPivot_PivotItem(pfOriginal As PivotField, _
                            Optional pi As PivotItem, _
                            Optional pfTemp As PivotField, _
                            Optional bDelete_wksTemp As Boolean = True, _
                            Optional bDelete_ptTemp As Boolean = False)

' If pfOriginal is a PageField, we'll simply turn .EnableMultipleItems to FALSE
' and select pi as a PageField

' Otherwise we'll
'   * create a temp copy of the PivotTable
'   * Make the field of interest a PageField
'   * Turn .EnableMultipleItems to FALSE and select pi as a PageField
'   * Add a Slicer to that PageField
'   * Connect that Slicer to pfOriginal, which will force it instantly to sync.
'     to pfTemp, meaning it shows just one item

' This is much faster than Iterating through a large PivotTable and setting all but
' one item to hidden, as outlined at http://dailydoseofexcel.com/archives/2013/11/14/filtering-pivots-based-on-external-ranges/



Const sRoutine = "FilterPivot_PivotItem"
Dim sc As SlicerCache
Dim bSlicerExists As Boolean
Dim ptOriginal As PivotTable
Dim ptTemp As PivotTable
Dim wksTemp As Worksheet
Dim bDisplayAlerts As Boolean
Dim lCalculation As Long
Dim bEnableEvents As Boolean
Dim bScreenUpdating As Boolean
Dim TimeTaken As Date


TimeTaken = Now()

Set ptOriginal = pfOriginal.Parent
With Application
    bScreenUpdating = .ScreenUpdating
    bEnableEvents = .EnableEvents
    lCalculation = .Calculation
    .ScreenUpdating = False
    .EnableEvents = False
    .Calculation = xlCalculationManual
End With


With pfOriginal
    If pi Is Nothing Then Set pi = .PivotItems(1)
    If .Orientation = xlPageField Then
        'Great: we're dealing with a field in the FILTERS pane, which let us
        ' select a singe item easily
        .EnableMultiplePageItems = False
        .CurrentPage = pi.Name
    Else
        ' For non PageFields we'll have to use a temp PivotTable and Slicer to quickly clear
        ' all but one PivotItem.

        'Check if pfOriginal already has a slicer connected
        ' If so, then we'll want to leave it in place when we're done
        bSlicerExists = Slicer_Exists(ptOriginal, pfOriginal)

        ' A temp PivotTable may aleady exist and have been passed in when the function was called
        ' Otherwise we'll need to create one.
        If pfTemp Is Nothing Then
            Set wksTemp = Sheets.Add
            Set ptTemp = ptOriginal.PivotCache.CreatePivotTable(TableDestination:=wksTemp.Range("A1"))
            Set pfTemp = ptTemp.PivotFields(.SourceName)
            'Set the SaveData state of this new PivotTable the same as the original PivotTable
            '(By default it is set to True, and is passed on to the original PivotTable when a Slicer is connected)
            If ptTemp.SaveData <> ptOriginal.SaveData Then ptTemp.SaveData = ptOriginal.SaveData
        Else
           Set ptTemp = pfTemp.Parent
            'Check if pfTemp already has a slicer conneced.
            If Not Slicer_Exists(ptTemp, pfTemp, sc) Then Set sc = ActiveWorkbook.SlicerCaches.Add(ptTemp, pfTemp)
        End If
        ptTemp.ManualUpdate = True

        With pfTemp
            .Orientation = xlPageField
            .EnableMultiplePageItems = False
            .CurrentPage = pi.Name
        End With
        ptTemp.ManualUpdate = False

        'Connect slicer on pfTemp to pfOriginal to pass through settings, then disconnect it
        sc.PivotTables.AddPivotTable pfOriginal.Parent
        If Not bSlicerExists Then
            sc.Delete
        Else
            sc.PivotTables.RemovePivotTable pfTemp.Parent
        End If
        If bDelete_wksTemp Then
            bDisplayAlerts = Application.DisplayAlerts
            Application.DisplayAlerts = False
            wksTemp.Delete
            Application.DisplayAlerts = bDisplayAlerts
        ElseIf bDelete_ptTemp Then ptTemp.TableRange2.ClearContents
        End If
    End If
End With

With Application
    .ScreenUpdating = bScreenUpdating
    .EnableEvents = bEnableEvents
    .Calculation = lCalculation
End With
TimeTaken = Now() - TimeTaken
Debug.Print Now() & vbTab & sRoutine & " took " & Format(TimeTaken, "HH:MM:SS") & " seconds."

End Sub

【讨论】:

  • 谢谢!这对我很有帮助!
  • 为了清楚起见,除了一个之外,没有任何代码可以更快地处理,对吧?
  • 对不起 Grafit,我不太明白你的问题。你能改写一下吗?
  • 如果我有几行代码可以让每个 pivotitem.visible = false,除了一个 pivotitem。 excel vba 处理我的代码没有比循环遍历数据中心项并一一检查更快的方法,对吧?我不能比循环遍历每个枢轴项更快地编写代码吗?
  • 是的,我发现了一种更快的方法,我在上面的链接中提到过。非常快:使用数据透视表的临时副本,将该数据透视表中感兴趣的字段设置为页面字段,将 .enablemultilpeitems 设置为 False 并为其添加切片器,然后将该切片器连接到原始数据透视表,这会强制原始数据透视表采用从属数据的设置。我将发布我为此编写的通用例程。
【解决方案3】:

例如,您可能需要在一开始就设置一个 true

.PivotItems(1) = true

然后你可以使用条件循环来设置这个项目应该是什么。

【讨论】:

    猜你喜欢
    • 2015-05-02
    • 1970-01-01
    • 2019-12-31
    • 2013-06-30
    • 2018-01-07
    • 1970-01-01
    • 2016-08-16
    • 2020-03-10
    • 2016-12-07
    相关资源
    最近更新 更多