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