无法获得枢轴项 class 的可见 属性
unable to get the visible property of the pivotitem class
我有两套代码。出于某种原因,在 第一个中我得到一个错误,而在 第二个中我没有。
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
我收到错误:"unable to get the visible property of the pivotitem class"
我读到我应该解决以下问题:
This is due to the Pivot table using the cached pivot items instead of
the current one. Make sure the table does not retain any old items. To
do so, right click on your pivot table, click on Data tab and set
"Number of itesm to retain per field" to "None". The code to do so in
VBA is:
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
这似乎没有解决我的问题。
1。您的 rows/columns 字段中是否有多个字段?
因为问题可能出在这里
PivotField中的所有PivotItem并不总是displayed/displayable因为它们在第二层,依赖于第一层。 为避免错误导致代码中断,您必须使用 错误处理程序.
只有从第一级找到的具有相应数据透视项的数据透视项才可显示(IE,您无法显示数据中未发生的情况)。
For instance you can't display the PivotItem "Car" at 2nd level
when the 1st level PivotItem is "Flying mode of transportation".
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,但你还试图显示所有其他 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
Grafit:您发布的两个代码片段非常做了不同的事情。第一个使除了值“(leeg)”之外的所有内容都可见。第二个使任何带有 "BSO" 的项目可见,并隐藏其他所有项目。两段代码都有问题。
关于您的第一个代码片段,如果您想显示除名为“(leeg)”的项目之外的所有项目,则无需遍历 PivotItems 集合(这在大型 Pivots 上确实很慢) .相反,只需这样做:
pf.ClearAllFilters
pf.PivotItems("leeg").visible = false
关于您的第二段代码,是的,错误可能是由 MissingItemsLimit 问题引起的,但如果代码试图隐藏 PivotItem 而循环期间当前没有其他 PivotItem 可见,也会发生此错误。例如,如果数据透视表只过滤了一项,例如 "Aardvark",那么因为 "Aardvark" 中没有 "BSO",代码将尝试隐藏它,并将然后出错,因为至少有一个 PiovtItem 必须始终保持可见。
所以你要做的是在 before 循环中添加一行,使 PivotItems 集合中的 last 项可见,所以您几乎可以保证一个项目在循环结束之前一直保持可见。
(当然,如果 "BSO" 没有出现在任何 PivotItems 中,那么当你去处理最后一个项目时仍然会得到错误。
此外,每当您遍历 PivotITems 集合时,您通常希望将 PT.ManualUpdate 设置为 True,这样数据透视表就不会在每个项目获得 hidden/unhidden。然后在例程结束时再次将 PT.ManualUpdate 设置为 False,然后告诉 Excel "I'm done...you can update these PivotTable totals now." 这通常会在例程速度方面产生惊人的差异。在大型 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
您可能需要在一开始就设置一个true,例如
.PivotItems(1) = true
然后你可以使用条件循环来设置这个项目它应该是什么。
我有两套代码。出于某种原因,在 第一个中我得到一个错误,而在 第二个中我没有。
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
我收到错误:"unable to get the visible property of the pivotitem class"
我读到我应该解决以下问题:
This is due to the Pivot table using the cached pivot items instead of the current one. Make sure the table does not retain any old items. To do so, right click on your pivot table, click on Data tab and set "Number of itesm to retain per field" to "None". The code to do so in VBA is:
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
这似乎没有解决我的问题。
1。您的 rows/columns 字段中是否有多个字段?
因为问题可能出在这里
PivotField中的所有PivotItem并不总是displayed/displayable因为它们在第二层,依赖于第一层。 为避免错误导致代码中断,您必须使用 错误处理程序.
只有从第一级找到的具有相应数据透视项的数据透视项才可显示(IE,您无法显示数据中未发生的情况)。
For instance you can't display the PivotItem "Car" at 2nd level
when the 1st level PivotItem is "Flying mode of transportation".
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,但你还试图显示所有其他 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
Grafit:您发布的两个代码片段非常做了不同的事情。第一个使除了值“(leeg)”之外的所有内容都可见。第二个使任何带有 "BSO" 的项目可见,并隐藏其他所有项目。两段代码都有问题。
关于您的第一个代码片段,如果您想显示除名为“(leeg)”的项目之外的所有项目,则无需遍历 PivotItems 集合(这在大型 Pivots 上确实很慢) .相反,只需这样做:
pf.ClearAllFilters pf.PivotItems("leeg").visible = false
关于您的第二段代码,是的,错误可能是由 MissingItemsLimit 问题引起的,但如果代码试图隐藏 PivotItem 而循环期间当前没有其他 PivotItem 可见,也会发生此错误。例如,如果数据透视表只过滤了一项,例如 "Aardvark",那么因为 "Aardvark" 中没有 "BSO",代码将尝试隐藏它,并将然后出错,因为至少有一个 PiovtItem 必须始终保持可见。
所以你要做的是在 before 循环中添加一行,使 PivotItems 集合中的 last 项可见,所以您几乎可以保证一个项目在循环结束之前一直保持可见。
(当然,如果 "BSO" 没有出现在任何 PivotItems 中,那么当你去处理最后一个项目时仍然会得到错误。
此外,每当您遍历 PivotITems 集合时,您通常希望将 PT.ManualUpdate 设置为 True,这样数据透视表就不会在每个项目获得 hidden/unhidden。然后在例程结束时再次将 PT.ManualUpdate 设置为 False,然后告诉 Excel "I'm done...you can update these PivotTable totals now." 这通常会在例程速度方面产生惊人的差异。在大型 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
您可能需要在一开始就设置一个true,例如
.PivotItems(1) = true
然后你可以使用条件循环来设置这个项目它应该是什么。