У меня есть несколько сводных таблиц на листе с множеством пустых строк для их разделения, чтобы, если кто-то внезапно получит много значений, он не перезаписал сводную таблицу внизу. Но чтобы пользователю не приходилось прокручивать довольно далеко вниз, чтобы увидеть другую сводную таблицу, у меня есть формула в столбце A, которая проверяет, заполнено ли что-либо в каждой строке, а затем написал некоторый VBA, чтобы скрыть строки, которые определила формула: пустой.
Проблема, с которой я столкнулся, заключается в том, что скрытие строк занимает 16 секунд, а это даже не большой диапазон. Есть ли лучший способ сделать это?
For Each cell In Range("A1:A200")
If cell.Value = "HIDDEN ROW" Then cell.EntireRow.Hidden = True
Next cell
VBA запускается в Worksheet_Change, и я запустил отладку, чтобы определить эту задержку, и результаты показывают:
Попробуйте следующее адаптированное решение. Скрытие одной строки за раз занимает много времени. Использование диапазона Union
и скрытие их всех одновременно должно быть намного быстрее:
Sub HideRows()
Dim cell As Range, uRng As Range
For Each cell In Range("A1:A200")
If cell.Value = "HIDDEN ROW" Then addToRange uRng, cell
Next cell
If Not uRng Is Nothing Then uRng.EntireRow.hiden = True
End Sub
Private Sub addToRange(rngU As Range, rng As Range)
If rngU Is Nothing Then
Set rngU = rng
Else
Set rngU = Union(rngU, rng)
End If
End Sub
Я изменил ваше решение здесь, чтобы добавить фиктивный столбец в конец, чтобы: 1. установить константы 2. скрыть строки, а затем 3. удалить фиктивный столбец, ваше решение творит чудеса для пакетных операций со строками/столбцами
Это идеально, красиво, компактно и значительно ускоряет процесс. Я надеялся, что мне не придется создавать отдельный модуль вне подпрограммы Worksheet_Change - возможно ли записать все это в одну и ту же подпрограмму?
Да, но это решение немного сложнее для случая или нескольких критериев. С точки зрения скорости, приведенное выше решение проще и немного быстрее для небольших диапазонов, как вы сказали...
@seaside_escape Не нужно создавать отдельный модуль! Вам следует заменить только код, который вы показываете в своем вопросе, на приведенный выше. Разумеется, скопировав функцию в тот же модуль листового кода. Если что-то еще не ясно, не стесняйтесь попросить разъяснений, конкретно описав проблему, с которой вы столкнулись...
Решение:
Я усовершенствовал подход FaneDuru, превратив его в функцию скрытия/удаления строк или столбцов. Там заявлена экономия времени. Это самое быстрое решение, которое я пробовал, я подчеркнул, что протестировал его с анализом около 150 тысяч строк, скрывая многие из них, и не потею.
Демо:
Код:
Sub Exec_AnalyzeRowsToHide()
Dim ArrRowsToHide() As String
Dim CounterRow As Long
ReDim ArrRowsToHide(1 To Cells.SpecialCells(xlCellTypeLastCell).Row, 1 To 1)
For CounterRow = 1 To 200
If Cells(CounterRow, 1).Value = "HIDDEN ROW" Then ArrRowsToHide(CounterRow, 1) = "Hide"
Next CounterRow
Call Exec_DeleteHideRowsOrColumns(ActiveSheet.Name, ArrRowsToHide, True, "Hide")
End Sub
Sub Exec_DeleteHideRowsOrColumns(TxtSheet As String, ArrTxtPlaceholderValues() As String, IsRowsToDo As Boolean, TxtCase As String)
'array parsed need to be like ArrNumRowsColsToDel(CounterArr, 1)
'Example usage for rows
'at least 6 rows used
'Dim arrnum() As String
' ReDim arrnum(1 To Cells.SpecialCells(xlCellTypeLastCell).Row, 1 To 1)
' arrnum(2, 1) = "Del": arrnum(4, 1) = "Del": arrnum(6, 1) = "Del"
' Call Exec_DeleteHideRowsOrColumns(ActiveSheet.Name, arrnum, True,"Del")
'Example usage for columns
'at least 6 columns used
'Dim arrnum() As String
' ReDim arrnum(1 To Cells.SpecialCells(xlCellTypeLastCell).Column, 1 To 1)
' arrnum(2, 1) = "Del": arrnum(4, 1) = "Del": arrnum(6, 1) = "Del"
' Call Exec_DeleteHideRowsOrColumns(ActiveSheet.Name, arrnum, False,"Del")
Dim NumLastRowOrColumn As Long
Dim CounterArr As Variant
Dim ArrDummy() As String
Dim NumRowsOrColsAdded As Long
Dim RangeDataSheet As Range
With Sheets(TxtSheet) ' 1. With Sheets(TxtSheet)
If IsRowsToDo = True Then ' 1. If IsRowsToDo = True
NumLastRowOrColumn = .Cells.SpecialCells(xlCellTypeLastCell).Column + 1
With .Cells(1, NumLastRowOrColumn).Resize(.Cells.SpecialCells(xlCellTypeLastCell).Row, 1) ' 2. With .Cells(1, NumLastRowOrColumn).Resize(.Cells.SpecialCells(xlCellTypeLastCell).Row, 1)
On Error Resume Next
.Value = ArrTxtPlaceholderValues
Select Case TxtCase
Case "Del"
.SpecialCells(xlCellTypeConstants).EntireRow.Delete
Case "Hide"
.SpecialCells(xlCellTypeConstants).EntireRow.Hidden = True: .Parent.Columns(NumLastRowOrColumn).Delete
End Select
End With ' 2. With .Cells(1, NumLastRowOrColumn).Resize(.Cells.SpecialCells(xlCellTypeLastCell).Row, 1)
.UsedRange
Else ' 1. If IsRowsToDo = True
NumLastRowOrColumn = .Cells.SpecialCells(xlCellTypeLastCell).Row + 1
With .Cells(NumLastRowOrColumn, 1).Resize(1, .Cells.SpecialCells(xlCellTypeLastCell).Column) ' 2. With .Cells(NumLastRowOrColumn, 1).Resize(1, .Cells.SpecialCells(xlCellTypeLastCell).Column)
.Value = Application.WorksheetFunction.Transpose(ArrTxtPlaceholderValues): DoEvents
Select Case TxtCase
Case "Del"
.SpecialCells(xlCellTypeConstants).EntireColumn.Delete
Case "Hide"
.SpecialCells(xlCellTypeConstants).EntireColumn.Hidden = True: .Parent.Rows(NumLastRowOrColumn).Delete
End Select
End With ' 2. With .Cells(NumLastRowOrColumn, 1).Resize(1, .Cells.SpecialCells(xlCellTypeLastCell).Column)
.UsedRange
End If ' 1. If IsRowsToDo = True
End With ' 1. With Sheets(TxtSheet)
End Sub
Отфильтровать значение, которое вы хотите скрыть? Возможно, это пригодится