Excel VBA-对大量单元格着色的有效方法

Excel VBA-对大量单元格着色的有效方法,vba,excel,Vba,Excel,我正在编写一段代码,根据单元格的可能值对其背景和字体值进行着色。我编写的代码工作得很好,但速度很慢,因为我需要处理大量的单元格(大约10*150k个单元格) 为了改进程序,我想加快功能 我得到的唯一想法是,我可以获得变量中的值,循环到变量中以获得相应的值行,并在定义的范围内将颜色应用到一行(对于一种情况)。但是关于单元格的数量,定义范围似乎有点复杂(我还没有尝试) 所以我想知道是否有人也遇到过同样的情况并找到了解决办法 非常感谢 如果需要VBA解决方案,则可以按格式搜索并处理相关单元格。这应该要

我正在编写一段代码,根据单元格的可能值对其背景和字体值进行着色。我编写的代码工作得很好,但速度很慢,因为我需要处理大量的单元格(大约10*150k个单元格)

为了改进程序,我想加快功能

我得到的唯一想法是,我可以获得变量中的值,循环到变量中以获得相应的值行,并在定义的范围内将颜色应用到一行(对于一种情况)。但是关于单元格的数量,定义范围似乎有点复杂(我还没有尝试)

所以我想知道是否有人也遇到过同样的情况并找到了解决办法


非常感谢

如果需要VBA解决方案,则可以按格式搜索并处理相关单元格。这应该要快得多

Sub FindFormatting()

    Dim Found As Range

    Application.FindFormat.Clear

    Application.FindFormat.Interior.Color = RGB(0, 106, 130)
    Set Found = FindAll(What:="", SearchWhat:=ActiveSheet, LookIn:=xlFormulas, LookAt:=xlPart, SearchFormat:=True)
    If Not Found Is Nothing Then Found.Font.Color = RGB(255, 255, 255)

    Application.FindFormat.Interior.Color = RGB(0, 138, 170)
    Set Found = FindAll(What:="", SearchWhat:=ActiveSheet, LookIn:=xlFormulas, LookAt:=xlPart, SearchFormat:=True)
    If Not Found Is Nothing Then Found.Font.Color = RGB(255, 255, 255)

    Application.FindFormat.Interior.Color = RGB(177, 209, 217)
    Set Found = FindAll(What:="", SearchWhat:=ActiveSheet, LookIn:=xlFormulas, LookAt:=xlPart, SearchFormat:=True)
    If Not Found Is Nothing Then Found.Font.Color = RGB(0, 0, 0)

    Application.FindFormat.Interior.Color = RGB(204, 225, 230)
    Set Found = FindAll(What:="", SearchWhat:=ActiveSheet, LookIn:=xlFormulas, LookAt:=xlPart, SearchFormat:=True)
    If Not Found Is Nothing Then Found.Font.Color = RGB(0, 0, 0)

End Sub

Function FindAll(What, _
    Optional SearchWhat As Variant, _
    Optional LookIn, _
    Optional LookAt, _
    Optional SearchOrder, _
    Optional SearchDirection As XlSearchDirection = xlNext, _
    Optional MatchCase As Boolean = False, _
    Optional MatchByte, _
    Optional SearchFormat) As Range

    'LookIn can be xlValues or xlFormulas, _
     LookAt can be xlWhole or xlPart, _
     SearchOrder can be xlByRows or xlByColumns, _
     SearchDirection can be xlNext, xlPrevious, _
     MatchCase, MatchByte, and SearchFormat can be True or False. _
     Before using SearchFormat = True, specify the appropriate settings for the Application.FindFormat _
     object; e.g. Application.FindFormat.NumberFormat = "General;-General;""-"""

    Dim SrcRange As Range
    If IsMissing(SearchWhat) Then
        Set SrcRange = ActiveSheet.UsedRange
    ElseIf TypeOf SearchWhat Is Range Then
        Set SrcRange = IIf(SearchWhat.Cells.Count = 1, SearchWhat.Parent.UsedRange, SearchWhat)
    ElseIf TypeOf SearchWhat Is Worksheet Then
        Set SrcRange = SearchWhat.UsedRange
    Else: SrcRange = ActiveSheet.UsedRange
    End If
    If SrcRange Is Nothing Then Exit Function

    'get the first matching cell in the range first
    With SrcRange.Areas(SrcRange.Areas.Count)
        Dim FirstCell As Range: Set FirstCell = .Cells(.Cells.Count)
    End With

    Dim CurrRange As Range: Set CurrRange = SrcRange.Find(What:=What, After:=FirstCell, LookIn:=LookIn, LookAt:=LookAt, _
        SearchDirection:=SearchDirection, MatchCase:=MatchCase, MatchByte:=MatchByte, SearchFormat:=SearchFormat)

    If Not CurrRange Is Nothing Then
        Set FindAll = CurrRange
        Do
            Set CurrRange = SrcRange.Find(What:=What, After:=CurrRange, LookIn:=LookIn, LookAt:=LookAt, _
            SearchDirection:=SearchDirection, MatchCase:=MatchCase, MatchByte:=MatchByte, SearchFormat:=SearchFormat)
            If CurrRange Is Nothing Then Exit Do
            If Application.Intersect(FindAll, CurrRange) Is Nothing Then
                Set FindAll = Application.Union(FindAll, CurrRange)
            Else: Exit Do
            End If
        Loop
    End If
End Function

您可以决定定义该列的使用范围并仅为其着色,而不是在一列中逐个单元格,即每列100多万个单元格

这可以通过以下方式实现:

Private Sub ApplyQtlColor(ByRef ws As Worksheet, ByVal qtlColumns As String)

    Dim myRange As Range
    Set myRange = ws.Range(qtlColumns)

    Dim i As Long
    Dim foundRange As Range
    For i = 1 To 4
        Set foundRange = FindAll(myRange, i)
        If Not foundRange Is Nothing Then
            'foundRange.Interior.Color = PickInteriorColor(i)
            foundRange.Font.Color = PickFontColor(i)
        End If
    Next i

End Sub
您可以通过某种功能选择FontColor和InteriorColor:

Public Function PickFontColor(i) As Long

    Select Case i
        Case 1
            PickFontColor = RGB(255, 255, 255)
        Case 2
            PickFontColor = RGB(255, 255, 255)
        Case Else
            PickFontColor = RGB(0, 0, 0)
    End Select

End Function
整个代码是这样调用的:
applyqtlcolorActiveSheet,“C:E”

代码使用
FindAll()
函数。因此,在某处添加此函数:

Function FindAll(SearchRange As Range, _
                 FindWhat As Variant, _
                 Optional LookIn As XlFindLookIn = xlValues, _
                 Optional LookAt As XlLookAt = xlWhole, _
                 Optional SearchOrder As XlSearchOrder = xlByRows, _
                 Optional MatchCase As Boolean = False, _
                 Optional BeginsWith As String = vbNullString, _
                 Optional EndsWith As String = vbNullString, _
                 Optional BeginEndCompare As VbCompareMethod = vbTextCompare) As Range

    Dim FoundCell As Range
    Dim FirstFound As Range
    Dim LastCell As Range
    Dim ResultRange As Range
    Dim XLookAt As XlLookAt
    Dim Include As Boolean
    Dim CompMode As VbCompareMethod
    Dim Area As Range
    Dim MaxRow As Long
    Dim MaxCol As Long
    Dim BeginB As Boolean
    Dim EndB As Boolean    

    CompMode = BeginEndCompare
    If BeginsWith <> vbNullString Or EndsWith <> vbNullString Then
        XLookAt = xlPart
    Else
        XLookAt = LookAt
    End If

    For Each Area In SearchRange.Areas
        With Area
            If .Cells(.Cells.Count).Row > MaxRow Then
                MaxRow = .Cells(.Cells.Count).Row
            End If
            If .Cells(.Cells.Count).Column > MaxCol Then
                MaxCol = .Cells(.Cells.Count).Column
            End If
        End With
    Next Area
    Set LastCell = SearchRange.Worksheet.Cells(MaxRow, MaxCol)

    On Error GoTo 0
    Set FoundCell = SearchRange.Find(what:=FindWhat, _
                                     after:=LastCell, _
                                     LookIn:=LookIn, _
                                     LookAt:=XLookAt, _
                                     SearchOrder:=SearchOrder, _
                                     MatchCase:=MatchCase)

    If Not FoundCell Is Nothing Then
        Set FirstFound = FoundCell
        Do Until False    ' Loop forever. We'll "Exit Do" when necessary.
            Include = False
            If BeginsWith = vbNullString And EndsWith = vbNullString Then
                Include = True
            Else
                If BeginsWith <> vbNullString Then
                    If StrComp(Left(FoundCell.Text, Len(BeginsWith)), BeginsWith, BeginEndCompare) = 0 Then
                        Include = True
                    End If
                End If
                If EndsWith <> vbNullString Then
                    If StrComp(Right(FoundCell.Text, Len(EndsWith)), EndsWith, BeginEndCompare) = 0 Then
                        Include = True
                    End If
                End If
            End If
            If Include = True Then
                If ResultRange Is Nothing Then
                    Set ResultRange = FoundCell
                Else
                    Set ResultRange = Application.Union(ResultRange, FoundCell)
                End If
            End If
            Set FoundCell = SearchRange.FindNext(after:=FoundCell)
            If (FoundCell Is Nothing) Then
                Exit Do
            End If
            If (FoundCell.Address = FirstFound.Address) Then
                Exit Do
            End If

        Loop
    End If

    Set FindAll = ResultRange

End Function
函数FindAll(搜索范围作为范围_
找到什么作为变体_
可选的LookIn为XlFindLookIn=xlValues_
可选的注视方式为XlLookAt=xlWhole_
可选的SearchOrder为XlSearchOrder=xlByRows_
可选MatchCase作为布尔值=False_
可选的BeginsWith As String=vbNullString_
可选EndsWith As String=vbNullString_
可选的BeginEndCompare作为VbCompareMethod=vbTextCompare)作为范围
作为射程的Dim-FoundCell
作为射程首次发现
将最后一个单元格设置为范围
Dim ResultRange As范围
暗XLookAt作为XlLookAt
Dim Include作为布尔值
将CompMode设置为VbCompareMethod
模糊区域作为范围
Dim MaxRow尽可能长
暗淡的马克斯科尔一样长
Dim BeginB作为布尔值
Dim EndB作为布尔值
CompMode=beginedcompare
如果以vbNullString开头或以vbNullString结尾,则
XLookAt=xlPart
其他的
XLookAt=LookAt
如果结束
用于SearchRange中的每个区域。区域
面积
如果.Cells(.Cells.Count).Row>MaxRow,则
MaxRow=.Cells(.Cells.Count).Row
如果结束
如果.Cells(.Cells.Count).Column>MaxCol,则
MaxCol=.Cells(.Cells.Count).Column
如果结束
以
下一个领域
设置LastCell=SearchRange.Worksheet.Cells(MaxRow,MaxCol)
错误转到0
Set FoundCell=SearchRange.Find(what:=FindWhat_
之后:=最后一个单元格_
LookIn:=LookIn_
瞧:=XLookAt_
SearchOrder:=SearchOrder_
匹配案例:=匹配案例)
如果不是FoundCell,那就什么都不是了
Set FirstFound=FoundCell
直到永远“假”循环。必要时我们会“退出”。
Include=False
如果BeginsWith=vbNullString,EndsWith=vbNullString,则
Include=True
其他的
如果以vbNullString开头,则
如果StrComp(左(FoundCell.Text,Len(BeginsWith)),BeginsWith,beginedcompare)=0,则
Include=True
如果结束
如果结束
如果EndsWith vbNullString,则
如果StrComp(Right(FoundCell.Text,Len(EndsWith)),EndsWith,beginedcompare)=0,则
Include=True
如果结束
如果结束
如果结束
如果Include=True,则
如果ResultRange什么都不是,那么
Set ResultRange=FoundCell
其他的
Set ResultRange=Application.Union(ResultRange,FoundCell)
如果结束
如果结束
设置FoundCell=SearchRange.FindNext(后面:=FoundCell)
如果(FoundCell为Nothing),则
退出Do
如果结束
如果(FoundCell.Address=FirstFound.Address),则
退出Do
如果结束
环
如果结束
Set FindAll=ResultRange
端函数

条件格式如何??比在每个单元格中循环快得多。@Nagarajand写的完全正确,你不需要VBA来完成这项任务。
Application.EnableAnimations=False
在第二行可以将它的速度提高10到100倍。@deaar这只是一个函数,但我有一个庞大的宏可以运行。@Chris-这就是这个想法。在结束子部分之前,编写
Application.EnableAnimations=True
以将它们取回。首先,非常感谢您抽出时间!我尝试了您在编辑之前所做的代码版本,出于某种原因,它只使用工作表中的一个值。我将尝试使用这个FindAll()版本(据我所知,它肯定会工作),它对于VBA解决方案非常有用!我真的很喜欢这个主意!但是正如其他人在前面的评论中所说,条件格式似乎是最快的解决方案。又来了@Chris-对于非VBA人员来说,条件格式可能也更容易操作。
Function FindAll(SearchRange As Range, _
                 FindWhat As Variant, _
                 Optional LookIn As XlFindLookIn = xlValues, _
                 Optional LookAt As XlLookAt = xlWhole, _
                 Optional SearchOrder As XlSearchOrder = xlByRows, _
                 Optional MatchCase As Boolean = False, _
                 Optional BeginsWith As String = vbNullString, _
                 Optional EndsWith As String = vbNullString, _
                 Optional BeginEndCompare As VbCompareMethod = vbTextCompare) As Range

    Dim FoundCell As Range
    Dim FirstFound As Range
    Dim LastCell As Range
    Dim ResultRange As Range
    Dim XLookAt As XlLookAt
    Dim Include As Boolean
    Dim CompMode As VbCompareMethod
    Dim Area As Range
    Dim MaxRow As Long
    Dim MaxCol As Long
    Dim BeginB As Boolean
    Dim EndB As Boolean    

    CompMode = BeginEndCompare
    If BeginsWith <> vbNullString Or EndsWith <> vbNullString Then
        XLookAt = xlPart
    Else
        XLookAt = LookAt
    End If

    For Each Area In SearchRange.Areas
        With Area
            If .Cells(.Cells.Count).Row > MaxRow Then
                MaxRow = .Cells(.Cells.Count).Row
            End If
            If .Cells(.Cells.Count).Column > MaxCol Then
                MaxCol = .Cells(.Cells.Count).Column
            End If
        End With
    Next Area
    Set LastCell = SearchRange.Worksheet.Cells(MaxRow, MaxCol)

    On Error GoTo 0
    Set FoundCell = SearchRange.Find(what:=FindWhat, _
                                     after:=LastCell, _
                                     LookIn:=LookIn, _
                                     LookAt:=XLookAt, _
                                     SearchOrder:=SearchOrder, _
                                     MatchCase:=MatchCase)

    If Not FoundCell Is Nothing Then
        Set FirstFound = FoundCell
        Do Until False    ' Loop forever. We'll "Exit Do" when necessary.
            Include = False
            If BeginsWith = vbNullString And EndsWith = vbNullString Then
                Include = True
            Else
                If BeginsWith <> vbNullString Then
                    If StrComp(Left(FoundCell.Text, Len(BeginsWith)), BeginsWith, BeginEndCompare) = 0 Then
                        Include = True
                    End If
                End If
                If EndsWith <> vbNullString Then
                    If StrComp(Right(FoundCell.Text, Len(EndsWith)), EndsWith, BeginEndCompare) = 0 Then
                        Include = True
                    End If
                End If
            End If
            If Include = True Then
                If ResultRange Is Nothing Then
                    Set ResultRange = FoundCell
                Else
                    Set ResultRange = Application.Union(ResultRange, FoundCell)
                End If
            End If
            Set FoundCell = SearchRange.FindNext(after:=FoundCell)
            If (FoundCell Is Nothing) Then
                Exit Do
            End If
            If (FoundCell.Address = FirstFound.Address) Then
                Exit Do
            End If

        Loop
    End If

    Set FindAll = ResultRange

End Function