【问题标题】:Select only (merged) cells which contain specified column(s)仅选择(合并)包含指定列的单元格
【发布时间】:2019-02-23 08:57:27
【问题描述】:

所以现在我正在开发 VBA 宏,它只能选择满足指定条件的单元格。问题是我有多个级别单元格的嵌套列表。每个级别由合并的列数决定。所以即 level 0ABCDE,level 1 包含合并列BCDE 的单元格,level 2仅合并 CDE,级别 3 DE 和级别 4 仅合并 E。请参阅附图以获得更好的可视化。问题是我不能只选择列,因为它会一次选择所有级别。

假设我只想选择 1 级 单元格(所以单元格是从列 BCDE * 合并的) - 我该如何在 VBA 中做到这一点?

谢谢

*) ABCD 在原始帖子中(参考评论)

【问题讨论】:

  • 第 1 级是 BCDE,而不是 ABCD?
  • 合并的单元格是一种害虫,应该避免。不要合并单元格。将数据放入每一行。您可以使用条件格式来使事物看起来仍然很好。
  • @FunThomas 是的,我的错误忘了提到我也有 0 级。将编辑这个。
  • @teylyn 是的,我同意,但是这是很多人使用的巨大 Excel 文件,所以很遗憾,我无法真正改变它。
  • 使用 centre across selection 而不是合并单元格。如果工作表太大而无法手动更改,您可以使用 VBA(在一次性脚本中)进行更改。

标签: excel vba range


【解决方案1】:

选择定义的级别

"... 所以 level 0ABCDElevel 1 包含合并列 BCDE 的单元格,level 2 仅合并 CDE3 级 DE4 级 仅合并 E。"

此方法使用MergeCellsMergeArea 属性选择给定Level如上定义)的所有项目,以通过帮助函数检查定义的Level 处的合并单元格bIsLevel().

应用方法

基本上是这样

  1. 检查定义范围内的每个单元格c *) 是否属于合并的单元格范围 (If c.MergeCells Then ...),
  2. 得到结果c.MergeArea.Address
  3. 通过帮助函数bIsLevel()检查找到的地址与想要的x级别地址

最近在第一个循环条件下编辑的注释

*) 由于MergeArea.Addresses 仅显示第一个包含的范围(合并范围中的顶部/左侧单元格),因此可以缩小搜索范围,例如.UsedRange 对应于Level + 1 的列;因此我将For Each c In Intersect(.UsedRange, .Columns(Level + 1)) 编辑为新的循环条件。

调用主程序SelectLevel

Procedure SelectLevel 有两个可选参数:(1) OP 定义的所需级别,(2) 合格的工作表名称。它可以通过以下示例语句调用(注意: 如果您不分配 第一个参数,则 level 0 假定为默认情况下,第二个参数默认为您选择的工作表名称,应更改为您当前的工作表名称)。

     SelectLevel 1     ' e.g. level 1 selects all merged cells of columns B:E

主程序SelectLevel

Sub SelectLevel(Optional Level& = 0, Optional ByVal SheetName$ = "MySheet")
Dim c As Range, rng As Range, i&
With ThisWorkbook.Worksheets(SheetName)
    For Each c In Intersect(.UsedRange, .Columns(Level + 1))
        If c.MergeCells Then
           If c.Address = Left(c.MergeArea.Address, Len(c.Address)) Then
              If bIsLevel(c, Level) Then
                 If rng Is Nothing Then
                    Set rng = c
                 Else
                    Set rng = Application.Union(rng, c)
                 End If
              End If
           End If
        End If
    Next
End With
' Execute selection of wanted level
If Not rng Is Nothing Then
       rng.Select
Else
       MsgBox "Found no LEVEL" & Level & " items.", vbExclamation, "No Selection"
End If
End Sub

辅助函数bIsLevel()

Function bIsLevel(currCell As Range, ByVal lvl&) As Boolean
Dim LevelAddress$, CellAddress$
Dim arr(): arr = Array("A", "B", "C", "D", "E")
LevelAddress = arr(lvl) & ":" & arr(UBound(arr))    ' define Level columns due to OP
CellAddress = Split(currCell.MergeArea.Address, "$")(1) & ":" & _
              Split(currCell.MergeArea.Address, "$")(3)
bIsLevel = (LevelAddress = CellAddress)

'If bIsLevel Then Debug.Print "cell " & currCell.Address & " in currcell.MergeArea " & currCell.MergeArea.Address & _
                         " (" & CellAddress & " equ./LEVEL" & lvl & " " & LevelAddress & ")"

End Function

【讨论】:

    【解决方案2】:

    此过程允许您选择任何给定的范围,以及您想要选择的级别。它通过将给定范围内的列数作为“0级”所需的列数来确定行的级别,并从中减去最后一列合并范围内的列数。

    为了帮助说明它是如何工作的,我添加了一个可选变量来写出每一行的级别(选定范围之后的两列)。默认情况下,选项是不显示级别。

    还添加了 T.M. 的建议,即检查 oSelectRange 是否可以防止在进行选择时发生崩溃。谢谢:)

    Sub Test()
       Call GetRowLevel(Sheet1.Range("A1:E8"), 4, True)
    End Sub
    
    Private Sub GetRowLevel(ByVal SearchRange As Range, ByVal Level As Integer, Optional ShowLevel As Boolean = False)
    
        Dim oLevel0 As Integer      ' Number of columns in Level 0
        oLevel0 = SearchRange.Columns.Count
    
        Dim oRowCounter As Long
        Dim oSelectRange As Range
        Set oSelectRange = Nothing
    
        For oRowCounter = 1 To SearchRange.Rows.Count
            If oLevel0 - SearchRange.Cells(oRowCounter, SearchRange.Columns.Count).MergeArea.Columns.Count = Level Then
    
                If oSelectRange Is Nothing Then
                    Set oSelectRange = SearchRange.Cells(oRowCounter, SearchRange.Columns.Count).MergeArea
                Else
                    Set oSelectRange = Application.Union(oSelectRange, SearchRange.Cells(oRowCounter, SearchRange.Columns.Count).MergeArea)
                End If
            End If
    
            'Testing: Show Levels
            If ShowLevel Then
                Sheet1.Cells(oRowCounter, SearchRange.Columns.Count + 2).Value = oLevel0 - SearchRange.Cells(oRowCounter, SearchRange.Columns.Count).MergeArea.Columns.Count
            End If
        Next
    
        If Not oSelectRange Is Nothing Then oSelectRange.Select
    End Sub
    

    【讨论】:

    • 缩小搜索范围并计算MergeArea 中的列的好点(顺便说一句,您的示例使用最后一级列,并且也允许不合并单元格用于第 4 级)我> +1。 - 最后一行代码的旁注:建议检查oSelectRange Is Nothing,以防没有找到单元格。
    • 感谢 T.M. 的反馈,我已经尝试了所有级别,它似乎即使在级别 4 也能正常运行(未合并单元格的合并单元格计数为 1)。我添加了显示每行级别、测试所有级别以及显示其结果的图像的可选功能。我还按照您的建议更新了最后一行,以防止在未找到单元格时出错。
    猜你喜欢
    • 1970-01-01
    • 2014-03-31
    • 2013-06-17
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多