Выберите один элемент слайсера из таблицы VBA

Я пытаюсь распечатать отчеты для выбранных держателей бюджета (выбранных из таблицы держателей бюджета), используя имя держателя бюджета для ввода в слайсер, который затем обновляет различные сводные таблицы. Проблема в том, что код выбирает всех держателей бюджета в слайсере, а не выбирает одного выбранного держателя бюджета, который я выбираю из таблицы.

Sub PrintPDFsSO()

    Dim Lobj As ListObject
    Dim Budholder As String
    Dim Path As String
    Dim x As Long, y As Long, Number_of_rows As Long
    Dim SourceBk As Workbook
    Dim SlicItem As SlicerItem, SlicDummy As SlicerItem, SlicCache As SlicerCache
    Dim pt As PivotTable, wb As Workbook, ws As Worksheet

    Set SourceBk = ThisWorkbook
    Set Lobj = SourceBk.Sheets("BudHolders").ListObjects("BudHolderList")
    Set SlicCache = SourceBk.SlicerCaches("Slicer_Budget_Holder")

    For x = 1 To Lobj.DataBodyRange.Rows.Count   'Budget Holders held in    BudHolderList Table

        Dim BudHolders()
        ReDim BudHolders(1 To Lobj.DataBodyRange.Rows.Count) 'as Budholders will only ever hold one budget hodler name, can this be simpified?
        Dim Counter As Long

        Counter = 1

        If Not Lobj.DataBodyRange.Rows(x).EntireRow.Hidden Then

            Budholder = Lobj.DataBodyRange(x, 3) 'Name of budget holder held in 3rd column of Budget Holder Table

            BudHolders(Counter) = Budholder      'Budholders holds the budget holder name

            Counter = Counter + 1

            ReDim Preserve BudHolders(1 To Counter - 1)

            ' Trying to stop slicers/pivot tables calculating so code setting new filter on budget name doesnt get stuck - but not working
            Application.Calculation = xlCalculationManual

            For Each ws In SourceBk.Sheets

                For Each pt In ws.PivotTables

                    pt.ManualUpdate = True

                Next pt

            Next ws

            'Code to change budget holder in slicer to next budget holder in selection from Table
            For y = LBound(BudHolders) To UBound(BudHolders)

                With SlicCache

                    .ClearManualFilter           'clears all filters and shows all items in budget holder slicer

                    For Each SlicItem In .SlicerItems

                        If BudHolders(y) <> SlicItem.Value Then 'Tests if the slicer item matches the current a value of budholder

                            SlicItem.Selected = False 'Grinding to a virtual halt on this line as it 'calculates and populates pivot table report'

                        End If

                    Next SlicItem

                End With

            Next y

            Application.Calculation = xlCalculationAutomatic

            For Each ws In SourceBk.Sheets

                For Each pt In ws.PivotTables

                    pt.ManualUpdate = False

                Next pt

            Next ws

            'Use budholder name which will populate some graphs etc in workbook with new figures
            SourceBk.Sheets("Graphs - Summary").Range("BudHolder_SG").Value = Budholder

            'Do Printing, saving etc
        End If

    Next

End Sub

person Chris    schedule 04.12.2017    source источник


Ответы (2)


Не могли бы вы изменить логику и скрыть тех, кто не нужен? Следующий код основан на выборе фильтров из таблицы и применении их к сводной таблице.

Примечание. Он сохранит все фильтры таблицы в массиве, а затем зациклит этот массив, чтобы применить фильтры по одному к срезу, связанному с опорной точкой.

Вы, безусловно, захотите сделать код более модульным и выделить в отдельные функции/подпрограммы хранение фильтров, зацикливание массива и любые отдельные действия, например. создание отчета при зацикливании массива на мобильном телефоне, поэтому отступы могут быть немного отключены.

Option Explicit

Sub PrintPDFs()

    Dim Lobj As ListObject
    Dim BudHolder As String
    Dim SlicItem As SlicerItem, SlicCache As SlicerCache
    Dim SourceBk As Workbook
    Dim x As Long

    Set SourceBk = ThisWorkbook

    'Picks up Table with budget holder details
    Set Lobj = SourceBk.Sheets("BudHolders").ListObjects("BudHolderList")

    'Picks up slicer which drives pivot tables in workbook
    Set SlicCache = SourceBk.SlicerCaches("Slicer_Budget_Holder")

    Dim BudHolders()
    ReDim BudHolders(1 To Lobj.DataBodyRange.Rows.Count)
    Dim counter As Long
    counter = 1


    For x = 1 To Lobj.DataBodyRange.Rows.Count

        If Not Lobj.DataBodyRange.Rows(x).EntireRow.Hidden Then ''Applies to items selected (ie visible) in the Budget Holder Table

            BudHolder = Lobj.DataBodyRange(x, 3)

            BudHolders(counter) = BudHolder

            counter = counter + 1

        End If

    Next x

    ReDim Preserve BudHolders(1 To counter - 1)


    For x = LBound(BudHolders) To UBound(BudHolders)

       With SlicCache

           .ClearManualFilter

           For Each SlicItem In .SlicerItems

               If BudHolders(x) <> SlicItem.Value Then

                   SlicItem.Selected = False

               End If

           Next SlicItem

       End With

       ‘Rest of code to do print PDF reports etc

    End Sub

Здесь таблица называется BudHolderList, сводная таблица — это сводная таблица 1, а слайсер называется Slicer_Budget_Holder.

Таблица:

Таблица

Вращаться:

Сводная таблица

person QHarr    schedule 04.12.2017
comment
Привет QHarr, я не думаю, что это будет работать с тем, что я делаю, потому что я беру держателя бюджета из отфильтрованного списка в таблице (список держателя бюджета), по одному и использую это имя держателя бюджета для управления различными другими отчеты (без использования сводных таблиц) в рабочей книге, которые затем копируются в новую книгу, сохраняются и распечатываются. Итак.. Я хочу использовать одного и того же держателя бюджета для фильтрации и создания сводных отчетов, создания всех не сводных отчетов и экспорта их в одном и том же цикле for/next, прежде чем перейти к следующему держателю бюджета в исходная таблица. Надеюсь, это имеет смысл! - person Chris; 05.12.2017
comment
Привет, QHarr. Я не могу понять, как работает строка If UBound(Filter(BudHolders, SlicItem.Value)) = -1. Вы можете объяснить? - person Chris; 05.12.2017
comment
BudHolders — это массив, содержащий имена элементов, выбранных в таблице. Фильтр =-1 - это место, где текущий элемент слайсера не найден в этом массиве. является скрытой строкой. - person QHarr; 05.12.2017
comment
Но я немного смущен вашим описанием того, что еще должно произойти. BudHolders — это массив, содержащий выбранных держателей бюджета из таблицы, вы можете зациклить этот массив, чтобы выполнить все шаги, которые вы описываете для каждого держателя бюджета. - person QHarr; 05.12.2017
comment
Хорошо, спасибо - я проверю это с более простой версией моей основной процедуры. Мне кажется странным, что для выбора одного элемента в слайсере требуется так много строк кода, но я вижу, что другие решения проблем со слайсерами также используют аналогичный подход - похоже, нужна новая функция! Может пройти день или два, прежде чем я найду время протестировать ваш код. - person Chris; 05.12.2017
comment
Привет. Боюсь, он сделал то, что, как я и предполагал, он выбрал всех видимых держателей бюджета в таблице держателей бюджета, а затем установил фильтр в слайсере для всех из них. Мне нужно, чтобы слайсер работал с бюджетом по одному, чтобы все сводные отчеты обновлялись для этого держателя бюджета, я распечатывал их и затем переходил к следующему держателю бюджета. Имя держателя бюджета хранится в переменной budholder — нет ли способа заставить слайсер работать, используя эту переменную и запуская всю процедуру через всеобъемлющий цикл? Спасибо за вашу помощь до сих пор - ваш код еще пригодится! - person Chris; 05.12.2017
comment
Трудно сказать не видя. Массив содержит все выбранные в данный момент. Вам просто нужно перестроить код так, чтобы цикл массива (BudHolders) был снаружи, а внутри — With SliCache... и цикл sliceritems; тест IF выполняется только против текущего элемента массива... Если BudHolders(counter) = SlicItem.Value, то делайте все.... Я думаю. Мне нужно будет посмотреть завтра, а потом опубликую с обновлением. - person QHarr; 05.12.2017
comment
Обновлены, чтобы отразить комментарии. Дайте мне знать, как это происходит. - person QHarr; 06.12.2017
comment
У меня дома только Mac, поэтому я не могу протестировать последний код, но я переставил циклы в предыдущей версии и установил массив так, чтобы он подбирал только одного держателя бюджета за раз, и это работало (ура!), но... цикл, очищающий все фильтры в слайсере, а затем проверяющий каждый элемент слайсера по отношению к держателю бюджета, означал, что программа останавливалась, пока сводные таблицы обновлялись при каждом изменении отфильтрованной строки, проверяемой на совпадение. Я попытался вставить строку ручного расчета перед тестом и строку pivottable.ManualUpdate = true, чтобы остановить обновление сводки, пока она проходила через цикл, но безрезультатно. - person Chris; 06.12.2017
comment
Нужно будет подумать, но вы также можете ввести Application.Wait для создания задержки (не идеальный способ, поскольку должно быть решение без введения задержки). - person QHarr; 06.12.2017
comment
Зацикливание массива и проверка не должны занимать много времени. Как вы расположите петли, может быть проблемой, но трудно сказать. - person QHarr; 06.12.2017
comment
Я отредактировал исходный код в исходном запросе выше, который показывает последнюю позицию. Это отлично работает для простого сводного/слайсера, но для большого набора данных и нескольких элементов в слайсере и нескольких сводных таблицах он застревает в цикле For Each SlicItem In .SlicerItems. - person Chris; 07.12.2017
comment
Это одна таблица, один слайсер и множество сводок? - person QHarr; 07.12.2017
comment
Исходные данные составляют около 80 000 строк, установленных в таблице с несколькими столбцами, являющимися вычисляемыми полями. Есть около 8 сводных таблиц, все они скопированы из первой, которую я создал, но используют разные поля и показывают разные представления, и их около 8 слайсеров, наиболее подключенных ко всем сводным таблицам, держатель бюджета — это тот, кто настраивает сводные данные для каждый из примерно 100 держателей бюджета. Размер файла составляет 30 МБ и сохраняется в формате .xlb. Я мог бы оценить исходные данные, чтобы уменьшить размер примерно до 18 МБ, хотя не думаю, что это проблема, поскольку исходные данные не пересчитываются. - person Chris; 07.12.2017
comment
Интересная ссылка на производительность слайсера здесь (powerpivotpro.com/2010/07 /slicers-and-pivot-update-performance), поэтому можно попробовать некоторые из предложенных здесь предложений по повышению скорости, хотя он предпочел бы способ временно приостановить обновление сводок до тех пор, пока слайсер не будет установлен с правильным держателем бюджета. - person Chris; 07.12.2017
comment
Похоже, у него есть задатки вопроса для сайта проверки кода (не могу размещать ссылку на mo, но является частью стека), где могут быть приняты вопросы по эффективности / структурированию рабочего кода. Попробуйте реализовать предложения из статьи, которую вы нашли, а затем, возможно, набросайте вопрос для проверки кода? Я/Другие, я уверен, будут рады просмотреть черновик. - person QHarr; 07.12.2017
comment
Как отправить черновик вопроса на проверку кода? Мне нужно отправить вопрос и новый код. - person Chris; 07.12.2017
comment
Для черновика я больше думал о том, чтобы просто поделиться здесь комментарием со ссылкой на вставку, и я мог бы посмотреть. Особенно, если эта тема переместится в чат. Проверка кода, вы должны опубликовать свой рабочий код для проверки, упомянув о проблемах со скоростью и запросив предложения по улучшению кода и скорости выполнения. Есть инструкция, как задать вопрос. - person QHarr; 07.12.2017
comment
Нужна помощь с этой выдержкой из приведенного выше кода: With sliccache .ClearManualFilter For Each SlicItem In .SlicerItems If UBound(Filter(BudHolders, SlicItem.Value)) = -1 Then SlicItem.Selected = False End If Next SlicItem End With В слайсере 100 элементов, и он практически останавливается в этой строке, поскольку он «вычисляет и заполняет отчет сводной таблицы». Цель состоит в том, чтобы заполнить слайсер одним держателем бюджета, взятым из таблицы, создать пакет отчетов и перейти к следующему. - person Chris; 07.12.2017
comment
надо будет посмотреть завтра. Был ли код в моем исправленном ответе таким же медленным? Обратите внимание, что мой код был обновлен. - person QHarr; 07.12.2017
comment
Извините - пропустил это. Я воспользуюсь вашей линией If BudHolders(x) <> SlicItem.Value и посмотрю, что произойдет. Но поскольку он все еще циклически перебирает все элементы в слайсере, я боюсь, что это не улучшит производительность. Я попытался удалить все слайсеры, оценил исходные данные, но никаких улучшений. Удаление многих ненужных листов/основ помогло, но все равно слишком медленно. - person Chris; 07.12.2017
comment
Похоже, здесь происходит гораздо больше. Вы всегда должны удалять лишние объекты, например. неиспользованные листы. Создайте сводные таблицы из того же кеша и т. Д. Я постараюсь найти время, чтобы завтра запустить несколько тестов. Обратите внимание, что я обновил весь код. - person QHarr; 08.12.2017
comment
Привет, я обновил исходный код (см. выше) с вашими предложениями, но все еще медленно. Обратите внимание, что я изменил ваш код, чтобы Budholders одновременно содержал только одного выбранного держателя бюджета, который затем используется в строке ‹›slicitem.value. Ваш код создает срез со всеми видимыми элементами, отображаемыми в исходной таблице держателя бюджета. Настоящая проблема остается в том, что цикл сравнения элементов слайсера проверяет текущего держателя бюджета в держателях почки против 175 держателей бюджета в наборе данных, и, похоже, есть некоторый расчет, выполняющий операцию слайсера, которая занимает около 0,5 секунды на каждого держателя бюджета. - person Chris; 08.12.2017
comment
PS Мне нужна помощь .. сообщение было моей неудачной попыткой запроса на проверку кода. Как вы, вероятно, можете сказать, я немного новичок в этом мире, но я настойчив, потому что вижу большие преимущества в раскалывании этого конкретного каштана :) - person Chris; 08.12.2017
comment
Я думаю, что у вас это неправильно: pt.ManualUpdate = True и pt.ManualUpdate = False. Кроме того, хранение в массиве по одному элементу за раз не дает повышения эффективности. - person QHarr; 08.12.2017
comment
Я все еще немного не уверен, почему вы изменили код из того, как работал мой цикл массива, я бы подумал, что лучше вставить ваши улучшения в предложенную структуру. Однако, если он работает быстрее для вас, то кто я должен сказать. Боюсь, pastebin не сохранил мое форматирование, но вот стартер для 10 в новом вопросе, возможно, для проверки кода pastebin.com/a5MY6JGb Не забывайте быть конкретными (прямо цитируйте сообщение о программном обеспечении, размеры/количество элементов), расскажите, что вы пробовали и каков был результат. Сделайте так, чтобы людям было легко помогать вам. - person QHarr; 08.12.2017
comment
Включите информацию, например, о количестве столбцов в таблице, чтобы люди имели более точное представление о размере рабочей нагрузки. - person QHarr; 08.12.2017
comment
Итак, приступим (pastebin.com/NWQM5mjh). Спасибо, что начали это. Не уверен, что будет дальше! - person Chris; 08.12.2017
comment
Выглядит хорошо, но убедитесь, что вы соответствуете используемым числам, например. Если это 175 распорядителей бюджета, это число должно быть указано во всем тексте (а не 170, как в настоящее время, это строки 27, 48 и 54 или v.v.). Удалить мой комментарий, оставшийся в (необходимо конкретное число) — строка 54. Что означает «оценил исходные данные»? Строки 37 и 56. Может быть, немного расширить, что это значит. Затем, отправляя сообщение на проверку кода, обязательно делайте отступ в коде и используйте подсветку и интервалы по мере необходимости. Если вы дадите мне знать, когда опубликуете, я могу посмотреть и помочь с редактированием. - person QHarr; 08.12.2017
comment
Готово — строки комментариев в коде стали немного беспорядочными. Мне нужно запустить ваш исправленный код по-вашему, чтобы я ничего там не пропустил. - person Chris; 08.12.2017
comment
В порядке. Дайте мне знать, когда вы отправите код для проверки (с тегом VBA), и я посмотрю. - person QHarr; 08.12.2017
comment
Просто запустил предложенную вами структуру на основной модели - та же проблема с задержкой в ​​​​работе со списком слайсеров. Офисный рождественский обед манит. Не уверен, насколько продуктивным я буду до конца дня! - person Chris; 08.12.2017
comment
О, Боже. У меня не было времени попробовать и проверить ваши оценки рабочей нагрузки. Извини. Попробую в обеденный перерыв. Между тем, возможно, отправьте сообщение в обзор кода, если вам удобно задать вопрос как есть. - person QHarr; 08.12.2017
comment
Следующий тупой вопрос... скопировать ссылку на pastebin в код-ревью? - person Chris; 08.12.2017
comment
Нет. Вы задаете вопрос и убеждаетесь, что пример завершен, т. е. содержит код. Взгляните на уже имеющиеся вопросы с тегом VBA и посмотрите, какие из них, по вашему мнению, просты для понимания и хорошо изложены. - person QHarr; 08.12.2017
comment
Обратите внимание, что этот Lobj.DataBodyRange.Rows.Count, вероятно, должен храниться в переменной, например. LobjCount, поэтому вы затем делаете For x = 1 To LobjCount, а другая ссылка становится ReDim BudHolders (1 To LobjCount) - person QHarr; 08.12.2017
comment
Спасибо. Отправленный запрос кода - я мог только пометить с помощью VBA. Ничего не видно на слайсерах или сводках - person Chris; 08.12.2017
comment
Я внес правку, которая ожидает проверки другими пользователями сайта. Удачи. - person QHarr; 08.12.2017
comment
Пока нет радости от сайта проверки кода, но я нашел обходной путь. Если я обновлю держателя бюджета в поле держателя бюджета в любой из сводных таблиц (убедившись, что множественный выбор отключен), ВСЕ сводные таблицы обновляются с новым держателя бюджета (поскольку они все связаны через слайсер?), и цикл занимает около 2 секунд, что меня вполне устроит. У меня достаточно времени, чтобы приготовить кофе, пока рутина выполняется для всех 170 бюджетников. Все еще кажется странным, что нет быстрого способа использовать маршрут слайсера, но я счастлив. - person Chris; 10.12.2017
comment
Это сработает! Хорошо сделано. Опубликовать как ответ, чтобы другие могли учиться на нем. - person QHarr; 10.12.2017

Я нашел обходной путь, работая с одной из сводных таблиц, а не со слайсером. Поскольку все таблицы связаны (т. е. все имеют держатель бюджета в качестве поля фильтра и связаны через слайсер), когда держатель бюджета обновляется в сводном поле в сводной таблице, он обновляет все сводные таблицы с помощью одинаковое значение PivotField.

Таким образом, код для замены кода слайсера в исходной задаче выглядит просто:

With sheets ("BudgetHolder").PivotTables("PivotTable1").PivotFields("BudgetHolder")
.ClearAllFilters
.CurrentPage=Budholder
End With
person Chris    schedule 11.12.2017