VBA - 创建“颜色检查范围”以反转循环

Posted

技术标签:

【中文标题】VBA - 创建“颜色检查范围”以反转循环【英文标题】:VBA - Creating a "Color Check Range" to Reverse Loop 【发布时间】:2021-03-17 17:22:42 【问题描述】:

目前有一个反向循环寻找cells.font.strikethrough = true

一旦找到,我将使用该单元格作为我的.find 的起点,以查找上面具有Interior. Color = RGB(0,0,0) 的第一个单元格并首先将该值复制/粘贴到目标,然后偏移具有删除一列并删除整行数据。

为了我最近糟糕的交流: 父单元格 = 黑色背景 子单元格 = 父单元格下方没有黑色背景的每个单元格

具有黑色背景的单元格永远不能与某些子单元格同时删除/删除,因为并非所有子单元格都会同时移动到另一个工作表。

数据填充到此工作簿中,如下所示:

 Parent
 child
 child
 child
 Parent
 child
 child
 child
 child
 child

等等。每个父级的子单元格的数量是未知的。

以上面的示例为例,当所有子单元格都已为父母双方移动/删除时,这会导致 2 个父母位于彼此上方/下方,除了手动删除行之外,无法删除它们。像这样:

Parent
Parent

导致我想要进行“父单元格颜色检查”的问题

总结:

当反向循环搜索删除线时,宏最终会穿过一个黑色背景的单元格

一旦发生这种情况,请检查该单元格上方是否有另一个黑色背景,然后继续检查上方,直到它碰到没有黑色背景的单元格,然后我想删除所有连续的黑色背景行。

我能想到这种情况的唯一直接问题:

Parent
Parent
Parent
Child (no strikethrough)

我认为上述逻辑最终会删除尚未删除的孩子的父母,这是我不想要的,我不知道如何防止。

子单元格将始终位于父单元下方,因此可能在第一个父单元的上方和下方进行另一位代码检查以查看子单元是否存在,如果没有子单元格,则使用该位置作为父单元检查的起始范围?我不知道,我的大脑很痛,这两天就要到期了!

抱歉啰嗦了这么久!这就是我现在正在使用的东西。

Private Sub CommandButton1_Click()

Dim ipWS As Worksheet, compWS As Worksheet
Dim compDest As Range, rrCell As Range
Dim i As Integer
Dim alastRow As Long

Set ipWS = ThisWorkbook.Worksheets("In Processing")
Set compWS = ThisWorkbook.Worksheets("Completed")


alastRow = ipWS.Cells(Rows.Count, 1).End(xlUp).Row


Dim rackRng As Range
Dim cellRng As Range

Set compDest = compWS.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)

Application.FindFormat.Interior.Color = RGB(0, 0, 0)


For i = alastRow To 1 Step -1

            
            If Range(Cells(i, 1), Cells(i, 1)).Font.Strikethrough = True Then
           
                Set rackRng = ipWS.Range(Cells(i, 1), Cells(i, 1).End(xlUp)).Find("*", , , , , xlPrevious, , , SearchFormat:=True)
                    rackRng.Copy compDest
                        Application.CutCopyMode = False
                
                Range(Cells(i, 1), Cells(i, Columns.Count).End(xlToLeft)).Copy compDest.Offset(0, 1)
                    Application.CutCopyMode = False
                
                        Set compDest = compDest.Offset(1, 0)
                    
                    Range(Cells(i, 1), Cells(i, 1)).EntireRow.Delete
            End If

Next i
            With compWS.Range("A:P")
                .Font.Strikethrough = False
                .ColumnWidth = 25
                .Font.Size = 14
                .WrapText = True
                .HorizontalAlignment = xlCenter
                .VerticalAlignment = xlVAlignCenter
            End With

End Sub

更新

此图显示删除线单元格正在“完成”,因此需要转移到“已完成”工作表。

将我当前的代码编程到按钮上,这是“已完成”工作表上的结果。

留下如下图所示的“处理中”表。

因为“12/3/2020 110”和“12/3/2020 96”的所有子单元格都已被删除,我正在寻找一种方法将代码添加到删除 2 个父单元格的按钮(仅当所有子单元格都已移至“已完成”工作表时)

【问题讨论】:

【参考方案1】:

使用格式标准复制和删除

守则

Option Explicit

Sub updateData()
    
    Const ProcName As String = "updateData"
    On Error GoTo clearError

    ' Source
    Const srcName As String = "In Processing"
    Const srcFirst As String = "D10"
    ' Destination
    Const dstName As String = "Completed"
    ' Workbook
    Dim wb As Workbook
    Set wb = ThisWorkbook
  
    ' Define Source First Cell.
    Dim cel As Range
    Set cel = wb.Worksheets(srcName).Range(srcFirst)
    ' Define Source Range assuming data is contiguous with an empty column
    ' to the right, and an empty row at the bottom. Data adjacent
    ' to the left and to the top is allowed.
    Dim rng As Range
    With cel.CurrentRegion
        Set rng = cel.Resize(.Rows.Count + .Row - cel.Row, _
            .Columns.Count + .Column - cel.Column)
    End With
    
    Dim CopyList As Object
    Set CopyList = CreateObject("System.Collections.ArrayList")
    Dim DeleteList As Object
    Set DeleteList = CreateObject("System.Collections.ArrayList")
    
    Dim i As Long          ' Source Counter
    Dim cCount As Long     ' Copy Counter
    Dim dCount As Long     ' Delete Counter
    Dim iCopied As Boolean ' Interior Color Row Copied
    Dim iRow As Long       ' Interior Color Row
    Dim sRow As Long       ' Strike Through Row
    
    ' Write the row numbers of the rows to be copied and/or deleted
    ' to the array lists.
    iRow = -1 ' Necessary for the second 'If' statement's logic to work.
    For Each cel In rng.Columns(1).Cells
        i = i + 1
        If cel.Interior.Color = RGB(0, 0, 0) Then
            If i - sRow - 1 = iRow Then
                dCount = dCount + 1
                DeleteList.Add iRow
            End If
            iRow = i
            sRow = 0
            iCopied = False
        ElseIf cel.Font.Strikethrough Then
            If Not iCopied Then
                cCount = cCount + 1
                CopyList.Add iRow
                iCopied = True
            End If
            cCount = cCount + 1
            dCount = dCount + 1
            CopyList.Add i
            DeleteList.Add i
            sRow = sRow + 1
        End If
    Next cel
    
    If cCount > 0 Then
        Application.ScreenUpdating = False
        Dim CopyRange As Range ' ByRef
        Dim DeleteRange As Range ' ByRef
        Dim RowNumber As Variant ' Has to be 'Variant'.
        ' Write to Destination Worksheet.
        For Each RowNumber In CopyList
            buildRange CopyRange, rng.Rows(RowNumber)
        Next RowNumber
        With wb.Worksheets(dstName)
            CopyRange.Copy .Cells(.Rows.Count, 1).End(xlUp).Offset(1, 1)
            With .Range("A:P")
                .Font.Strikethrough = False
                .ColumnWidth = 25
                .Font.Size = 14
                .WrapText = True
                .HorizontalAlignment = xlCenter
                .VerticalAlignment = xlVAlignCenter
            End With
        End With
        ' Delete rows in Source Worksheet.
        DeleteList.Sort
        For Each RowNumber In DeleteList
            buildRange DeleteRange, rng.Columns(1).Cells(RowNumber)
        Next RowNumber
        DeleteRange.EntireRow.Delete
        Application.ScreenUpdating = True
        MsgBox "Number of copied rows: " & cCount & vbLf _
            & "Number of deleted rows: " & dCount, vbInformation, "Update"
    Else
        MsgBox "No rows deleted.", vbInformation, "Update"
    End If

ProcExit:
    Exit Sub

clearError:
    Debug.Print "'" & ProcName & "': Unexpected Error!" & vbLf _
              & "    " & "Run-time error '" & Err.Number & "':" & vbLf _
              & "        " & Err.Description
    Resume ProcExit

End Sub


Sub buildRange( _
        ByRef BuiltRange As Range, _
        AddRange As Range)
    If Not AddRange Is Nothing Then
        If Not BuiltRange Is Nothing Then
            Set BuiltRange = Union(BuiltRange, AddRange)
        Else
            Set BuiltRange = AddRange
        End If
    End If
End Sub

【讨论】:

如果您看到了之前的评论,我们很抱歉造成混淆。用户错误。 但是,出于测试目的,我将 srcFirst 单元格更改为“A1:A10”。我从 cmd 按钮调用了 updataData 子,但什么也没发生。抱歉,我大约 2 个月前开始使用 vba,而我了解代码在做什么,有些部分我根本不熟悉。如果这有助于填补我有限的知识空白,我会用图片更新我的帖子。 srcFirst 必须设置为 A1 或数据开始的位置:仅一个单元格。上传一两张图片总是一个好主意,例如之前和之后。 再次道歉,我一开始就应该这样做。

以上是关于VBA - 创建“颜色检查范围”以反转循环的主要内容,如果未能解决你的问题,请参考以下文章

寻找Word VBA代码以使用当前默认高亮颜色突出显示文本

是否可以以编程方式反转图像的颜色?

Word VBA - 通过样式应用备用字体颜色不适用于已应用直接格式(字体颜色)的文本

使用 VBA 进行颜色填充,以单元格值为条件

在 VBA 中的电子表格对内循环

将数组加载到记录集中以循环以增加值 vba 访问