首页 文章

无法获取pivotitem类的visible属性

提问于
浏览
1

我有两套代码 . 出于某种原因,在 first one I get an errorsecond one I don't 中 .

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

我收到错误:“无法获取pivotitem类的可见属性”

我读过我应该解决以下问题:

这是由于数据透视表使用缓存的透视项而不是当前的透视项 . 确保表格不保留任何旧项目 . 要执行此操作,请右键单击数据透视表,单击“数据”选项卡,然后将“每个字段保留的数量”设置为“无” . 在VBA中执行此操作的代码是:Dim pt As PivotTable 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

这似乎并没有解决我的问题 .

3 回答

  • 2

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

    因为问题可能来自于此 .

    数据透视图中的所有数据透视表都不会始终显示/显示,因为它们位于第二级,具体取决于第一级 . 为避免因错误导致代码中断,您必须使用 Error Handler .

    只显示与第一级相应PivotItem一起找到的PivotItems(IE无法显示数据中未发生的情况) .

    例如,当第一级PivotItem为“飞行模式”时,您无法在第2级显示PivotItem“Car” .


    2.刷新PivotCache

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

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

    3.代码逻辑

    之后看着你的代码,我有点困惑,因为你正在做的是隐藏一个由他的名字找到的特定PivotItem,但你也试着 display every other 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
    
  • 2

    Grafit:你发布的两个代码片段做了不同的事情 very . 除了值"(leeg)"之外,第一个使所有内容都可见 . 第二个使得"BSO"中的任何项目都可见,并隐藏其他所有项目 . 两位代码都存在问题 .

    关于你的第一个代码片段,如果你想显示除了一个名为“(leeg)”的项目之外的所有项目,那么就没有必要迭代PivotItems集合(在大型Pivots上它真的很慢) . 相反,只需这样做:

    pf.ClearAllFilters pf.PivotItems(“leeg”) . visible = false

    关于你的第二段代码,那么错误可能是由MissingItemsLimit问题引起的,但是如果代码试图隐藏PivotItem而在循环期间当前没有其他PivotItems可见的情况下也会发生错误 . 例如,如果你过滤了数据透视表,只说一个项目,如“Aardvark”,那么因为“Aardvark”中没有“BSO”,代码会尝试隐藏它,然后会出错,因为在至少有一个PiovtItem必须始终保持可见状态 .

    因此,您需要做的是在循环之前添加一行,使PivotItems集合中的最后一项可见,这样您几乎可以保证在循环结束之前一个项目仍然可见 .

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

    此外,每当您遍历PivotITems集合时,通常需要将PT.ManualUpdate设置为True,以便在每个项目被隐藏/取消隐藏后,数据透视表不会尝试更新数据透视表中的总计 . 然后在例程结束时再次将PT.ManualUpdate设置为False,然后告诉Excel“我已经完成了......您现在可以更新这些数据透视表总计 . ”这通常会使您的日常工作速度产生惊人的差异 . 在大型Pivots上,您将节省大量时间 .

    我写了一篇文章,在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
    
  • 0

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

    .PivotItems(1) = true
    

    然后,您可以使用条件循环来设置它应该是的项目 .

相关问题