find first and last visible row in specific range + border around range(first:last)

huangapple go评论60阅读模式
英文:

find first and last visible row in specific range + border around range(first:last)

问题

这似乎是一个难以找到的主题,或者是我的谷歌技能再次让我失望。

我有一个表格,它在C31:C150范围内包含带有数字的方向...例如,C31:C55有N10、N11、N12,C56:C75有S40、41、42等。根据列D中相邻单元格是否为空,辅助列BA中包含填充时为1,否则为0。然后,我隐藏了所有包含列BA中0的行。由于这是一个动态过程,它经常会导致围绕方向范围(C31:C55;C56:C75;等等)的边框出现问题。
在我的示例中,只有第一个范围的C31可见。在第二个范围中,C56、C57、C60、C63、C64、C65、C72、C73可见。
我的目标是在C31和C56:C73周围加上边框。实际上,这是关于在列C到J周围加边框,但我猜或希望我可以自己做这个“小”调整。

有人有想法我如何解决这个问题吗?

我找到并尝试了以下两种方法:

Sheets("sheet1").Range("C56:J75").SpecialCells(xlCellTypeVisible).BorderAround _
ColorIndex:=0, Weight:=xlMedium

这不幸地将范围拆分为多个区域,一旦发现隐藏行(C56:C57;C60;C63:C65;C72:C73),就会拆分成多个区域。是否有办法可以提取上下端的行号?比如left(56),right(73),然后将它们合并?

第二种方法是:

Dim StartRow As Long, EndRow As Long
With Sheets("sheet1")
    StartRow = .Range("BA56:BA75").Find(what:=1, after:=.Range("BA56")).Row
    EndRow = .Range("BA56:BA75").Find(what:=1, after:=.Range("BA56"), SearchDirection:=xlPrevious).Row
End With

在描述的示例中,这给我startrow 61?!?!?!怎么回事???????
和endrow 71?!??它们都是隐藏的行...但是对于C31,代码工作正常(我猜它只适用于分组数据)。

所以,在创建这个问题时,自动搜索找到了这个:

Sub main()
    Dim firstCell As Range, lastCell As Range
    Set firstCell = first_non_blank_visible_cell(Range("$C$3:$C$5,$C$100:$C$64000"))
    Set lastCell = last_non_blank_visible_cell(Range("$C$3:$C$5,$C$100:$C$64000"))
    Debug.Print firstCell.Address
    Debug.Print lastCell.Address
End Sub

Function first_non_blank_visible_cell(rng As Range)
    On Error Resume Next
    Set rng = rng.SpecialCells(xlCellTypeVisible)
    Set rng = rng.SpecialCells(xlCellTypeConstants)
    With rng.Areas(1)
        Set first_non_blank_visible_cell = .Cells(1)
    End With
End Function

Function last_non_blank_visible_cell(rng As Range)
    On Error Resume Next
    Set rng = rng.SpecialCells(xlCellTypeVisible)
    Set rng = rng.SpecialCells(xlCellTypeConstants)
    With rng.Areas(rng.Areas.Count)
        Set last_non_blank_visible_cell = .Cells(.Cells.Count)
    End With
End Function

它起初有效,然后我第二次更改了范围以进行测试,它就坏了。无法让它恢复正常工作,甚至不在它曾经工作的范围内。lol。这是怎么可能的?

英文:

this seems to be a hard to find topic or my google skills left me once again.

I have a sheet, it has directions with numbers in Range(C31:C150)... e.g. C31:C55 has N10, N11, N12,... C56:C75 has S40, 41, 42, etc.. Depending on if the neighbour cell in column D is empty, the helper column BA contains a 1 if filled or 0 if empty. I then hide all rows containing a 0 in the column BA.
Because this is a dynamic process it often messes up the borders around the directions ranges (C31:C55;C56:C75;etc.).
In my example, only C31 from the first range is visible. In the 2nd range C56,57,60,63,64,65,72,73 are visible.
My goal is to get a border around C31 and C56:C73. actually its about getting a border around column C* to J*, but i guess or hope that i can do that "little" adjustment myself.

Anyone has an idea how i can approach this?

I found and tried these 2 approaches:

Sheets("sheet1").Range("C56:J75").SpecialCells(xlCellTypeVisible).BorderAround _
ColorIndex:=0, Weight:=xlMedium

this sadly splits the range into multiple areas, as soon as a hidden row is found (C56:C57;C60;C63:C65;C72:C73)
is there a way i can extract the row number of the upper and lower end? like left(56), right(73) and then combine both?

2nd approach was

Dim StartRow As Long, EndRow As Long
With Sheets("sheet1")
    StartRow = .Range("BA56:BA75").Find(what:=1, after:=.Range("BA56")).Row
    EndRow = .Range("BA56:BA75").Find(what:=1, after:=.Range("BA56"), SearchDirection:=xlPrevious).Row
End With

with the described example this gives me startrow 61?!?!?!??! WHat???
and endrow 71?!??! both hidden rows... but the code worked properly for C31 (i guess it only works with grouped data).

so while creating this question the automatic search found this:

Sub main()
    Dim firstCell As Range, lastCell As Range
    Set firstCell = first_non_blank_visible_cell(Range("$C$3:$C$5,$C$100:$C$64000"))
    Set lastCell = last_non_blank_visible_cell(Range("$C$3:$C$5,$C$100:$C$64000"))
    Debug.Print firstCell.Address
    Debug.Print lastCell.Address
End Sub

Function first_non_blank_visible_cell(rng As Range)
    On Error Resume Next
    Set rng = rng.SpecialCells(xlCellTypeVisible)
    Set rng = rng.SpecialCells(xlCellTypeConstants)
    With rng.Areas(1)
        Set first_non_blank_visible_cell = .Cells(1)
    End With
End Function

Function last_non_blank_visible_cell(rng As Range)
    On Error Resume Next
    Set rng = rng.SpecialCells(xlCellTypeVisible)
    Set rng = rng.SpecialCells(xlCellTypeConstants)
    With rng.Areas(rng.Areas.Count)
        Set last_non_blank_visible_cell = .Cells(.Cells.Count)
    End With
End Function

It worked at first, then i changed the range a second time for testing and it broke. cant get it back to work, not even in the range it used to work. lol. how is this possible

答案1

得分: 1

有点比我想象的复杂,但仍然可以实现:

Sub DoBordersAroundVisibleRows()
    Dim rF As Range, rL As Range, rw As Range, el
    Dim ws As Worksheet
    
    Set ws = ActiveSheet
    Application.ScreenUpdating = False '加快速度
    ws.Range("C31:J128").Borders.LineStyle = xlNone
    
    '循环处理范围中的每个“块”
    For Each el In Array("C31:J40", "C41:J55", "C55:J75", "C76:J95", _
                        "C96:J102", "C103:J114", "C115:J128")
        Set rF = Nothing '重置第一个/最后一个可见行
        Set rL = Nothing
        For Each rw In ActiveSheet.Range(el).Rows '循环处理块中的行
            If Not rw.EntireRow.Hidden Then '行可见?
                If rF Is Nothing Then '第一行上方添加顶部边框
                    Set rF = rw
                    ApplyBorders rF, xlEdgeTop
                End If
                Set rL = rw
                ApplyBorders rL, xlEdgeLeft, xlEdgeRight '所有行添加左/右边框
            End If
        Next rw
        If Not rF Is Nothing Then
            ApplyBorders rL, xlEdgeBottom '最后一行添加底部边框
        End If
    Next el
End Sub

'将所有提供的边框应用到范围' rng '
Sub ApplyBorders(rng As Range, ParamArray bordersToApply() As Variant)
    Dim i As Long
    For i = 0 To UBound(bordersToApply)
        With rng.Borders(bordersToApply(i))
            .LineStyle = xlContinuous
            .ColorIndex = xlAutomatic
            .TintAndShade = 0
            .Weight = xlMedium
        End With
    Next i
End Sub
英文:

A bit trickier than I'd thought but still possible:

Sub DoBordersAroundVisibleRows()
    Dim rF As Range, rL As Range, rw As Range, el
    Dim ws As Worksheet
    
    Set ws = ActiveSheet
    Application.ScreenUpdating = False 'speed up
    ws.Range("C31:J128").Borders.LineStyle = xlNone
    
    'loop over each "block" in the range
    For Each el In Array("C31:J40", "C41:J55", "C55:J75", "C76:J95", _
                        "C96:J102", "C103:J114", "C115:J128")
        Set rF = Nothing 'reset first/last visible rows
        Set rL = Nothing
        For Each rw In ActiveSheet.Range(el).Rows 'loop rows in block
            If Not rw.EntireRow.Hidden Then       'row is visible?
                If rF Is Nothing Then             'first row gets a top border
                    Set rF = rw
                    ApplyBorders rF, xlEdgeTop
                End If
                Set rL = rw
                ApplyBorders rL, xlEdgeLeft, xlEdgeRight 'all rows get R/L borders
            End If
        Next rw
        If Not rF Is Nothing Then
            ApplyBorders rL, xlEdgeBottom 'last row gets bottom border
        End If
    Next el
End Sub

'Apply all borders supplied to `bordersToApply` to range `rng`
Sub ApplyBorders(rng As Range, ParamArray bordersToApply() As Variant)
    Dim i As Long
    For i = 0 To UBound(bordersToApply)
        With rng.Borders(bordersToApply(i))
            .LineStyle = xlContinuous
            .ColorIndex = xlAutomatic
            .TintAndShade = 0
            .Weight = xlMedium
        End With
    Next i
End Sub

huangapple
  • 本文由 发表于 2023年7月12日 23:40:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76672326.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定