Скрыть строки таблицы *, если * любой из 3 столбцов (в этой строке) не является пустым - PullRequest
0 голосов
/ 28 ноября 2018

Я создал этот код, и он работает нормально.Однако я ожидаю, что должен быть более элегантный способ встраивания диапазона 'c' в функцию Evaluate, а не то, как я использовал 'r', чтобы определить номер строки, и встроить его в ссылку.

(Я учу).Копия (очень урезанного) xlsm доступна здесь: https://www.dropbox.com/s/e6pcugqs4zizfgn/2018-11-28%20-%20Hide%20table%20rows.xlsm?dl=0

Sub HideTableRows()

Application.ScreenUpdating = False

Dim c As Range
Dim r As Integer

For Each c In Range("ForecastTable[[Group]:[Item]]").Rows
    r = c.Row
    If Application.Evaluate("=COUNTA(B" & r & ":D" & r & ") = 0") = True Then
        c.EntireRow.Hidden = True
    Else: c.EntireRow.Hidden = False
    End If
Next c

Application.ScreenUpdating = True

End Sub

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

Немного перевернув логику, почему бы не отфильтровать эти три столбца для пробелов, а затем спрятать все видимые отфильтрованные пустые строки за один раз?

Примерно так:

Sub DoTheHide()

    Dim myTable As ListObject
    Set myTable = Sheet4.ListObjects("ForecastTable")
    With myTable.Range
        .AutoFilter Field:=1, Criteria1:="="
        .AutoFilter Field:=2, Criteria1:="="
        .AutoFilter Field:=3, Criteria1:="="
    End With

    Dim rowsToHide As Range
    On Error Resume Next
        Set rowsToHide = myTable.DataBodyRange.SpecialCells(xlCellTypeVisible)
    On Error GoTo 0

    myTable.AutoFilter.ShowAllData

    If Not rowsToHide Is Nothing Then
        rowsToHide.EntireRow.Hidden = True
    End If

End Sub
0 голосов
/ 28 ноября 2018

Поскольку c используется для итерации по строкам, и каждая строка содержит 3 рассматриваемые ячейки, ("=COUNTA(B" & r & ":D" & r & ") = 0") эквивалентно ("=COUNTA(" & c.Address & ") = 0").Но лучше напрямую использовать функцию Worksheet.

Следует отметить, что Range("[Table]") will return the proper result as long as the table is in the ActiveWorkbook. It would be better to use ThisWorkbook.Worksheets ("Sheet1"). Range ("[Table]") `.

Sub HideTableRows()

    Application.ScreenUpdating = False

    Dim row As Range, target As Range

    With Range("ForecastTable[[Group]:[Item]]")
        .EntireRow.Hidden = False
        For Each row In .rows
            If Application.WorksheetFunction.CountA(row) = 0 Then
                If target Is Nothing Then
                    Set target = row
                Else
                    Set target = Union(target, row)
                End If
            End If
        Next
    End With

    If Not target Is Nothing Then target.EntireRow.Hidden = True
    Application.ScreenUpdating = True

End Sub
0 голосов
/ 28 ноября 2018

Нет конкретного вопроса / проблемы, но вот мои предложенные улучшения кода.

  • В частности, я бы не стал выполнять процедуру Hidden, пока у вас не появятся все строки.Таким образом, вы больше не будете делать то, что нужно выполнить только один разЭто всегда будет наилучшей практикой при обработке и манипулировании данными. Внесите изменения в лист ПОСЛЕ того, как вы определили диапазон.
  • С вышеуказанным изменением вам не нужно выключать ScreenUpdating.
  • Функция Evaluate в порядке, но, возможно, isEmpty - лучший вариант.Вероятно, есть несколько более быстрые методы, возможно, проверка нескольких операторов if, но это занимает доли секунды в тысячах строк (вероятно, не стоит исследовать).
  • Технически вам не нужно переходить на rows.Вы можете обойтись одной ячейкой в ​​строке, а затем проверить следующие две, см. Использование Offset для генерации этого диапазона.Это также создает более динамичный характер, чем использование жестко закодированных столбцов («A» / «B» ... и т. Д.)
  • Long рекомендуется более Integer, но это довольно мало, и яЯ только упомянул это , потому что я написал об этом здесь. . Технически вам даже не нужно это с вышеуказанными изменениями.

Вот код:

Sub HideTableRows()
    Dim c As Range, hIdeRNG As Range, WS As Worksheet

    'based on OP xlsm file.
    Set WS = Sheet4


    'used range outside of used range to avoid an if-statement on every row
    Set hIdeRNG = WS.Cells(Rows.Count, 1)

    'loops through range of single cells for faster speed
    For Each c In Range("ForecastTable[Group]").Cells

        If IsEmpty(Range(c, c.Offset(0, 2))) = 0 Then
            'only need a single member in the row.
            Set hIdeRNG = Union(hIdeRNG, c)
        End If

    Next c

    'Hides rows only if found more than 1 cell in loop
    If hIdeRNG.Cells.Count > 1 Then
        Intersect(WS.UsedRange, hIdeRNG).EntireRow.Hidden = True
    End If

End Sub

Заключительная мысль: В Excel, предположительно в начале 2019 года, появятся некоторые важные усовершенствования, которые могут быть полезны для ситуаций такого типа, если вы ищете решение, отличное от VBA. Нажмите здесь длябольше информации от MS.

...