英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论