Betinget formatering med VBA makroer
Betinget formatering i Excel er smart til at fremhæve celler, der opfylder eller ikke opfylder bestemte kriterier - fx værdier over en given grænse.
Imidlertid kan det have sine fordele at bruge VBA makroer i stedet, fx hvis du vil tælle de celler, som udløser betinget formatering (fx en bestemt baggrundsfarve).
En af mine kollegaer har et regneark, som dagligt importerer kvalitets- og procesdata, 24 rækker for hver dag og X kolonner, og han brugte betinget formatering til at farve celler røde, hvis sådan og sådan.
En dag sprugte han, om jeg kunne lave en makro, der talte de røde celler i hver kolonne.
Uvidende svarede jeg: "Ja, selvfølgelig" og troede, at det ville være en nem sag. Jeg tog fejl!
Når en celle er farvet med betinget formatering, er det at tælle en meget kompliceret sag, hvis det er muligt, og det var langt nemmere at skrive en makro, som læste hans betingelser og formaterede cellerne.
Så er det ingen sag at tælle cellerne, som får en bestemt farve.
Herunder er der et eksempel på hvordan. Du kan kopiere koden her på siden og sætte den ind i et VBA-modul, eller du kan downloade et zipkomprimeret regneark med eksemplet. Regnearket er med engelsk tekst.
Der er mange måder at gøre det på, men i dette eksempel læser makroen:
- Om en kolonne skal formateres betinget
- Nedre og øvre grænse for værdierne i hver kolonne
- Valgbart: Om formateringen har en kontrolværdi (her driftstid)
I eksempel-regnearket ser tabellen således ud:
Eksemplet har en lav og/eller høj grænse for hver kolonne. Hvis en celleværdi fx er under den lave grænse, farves den rød, og antallet af røde celler i kolonnen indsættes nederst.
Hvis en grænseværdi er tom, testes der ikke for den. Det giver 4 scenarier:
Nedre grænse = True og Øvre grænse = True
Nedre grænse = False og Øvre grænse = False
Nedre grænse = False og Øvre grænse = True
Nedre grænse = True og Øvre grænse = False
Intet forhindrer dig i at tilføje en Lav lav og Høj høj, men så bliver der 16 scenarier at tjekke.
Hvis du definerer en kontrolkolonne (med fx driftstid), vil værdier uden for grænserne blive ignoreret, hvis kontrolværdien ikke er = 1.
Koden benytter Ranges og indlejrede ForEach Next løkker, og der er også en kontrol af, om en given værdi er et heltal (Integer) eller ej.
Hvis du udvider tabellen mod højre, vil makroen automatisk tage de nye kolonner med.
Lad os komme i gang:
Sub FormatCells()
Dim bL As Boolean
Dim bH As Boolean
Dim bRed As Boolean
Dim bCheck As Boolean
Dim lCols As Long
Dim lActiveCol As Long
Dim lOffset As Long
Dim lRedCount As Long
Dim dHigh As Double
Dim dLow As Double
Dim rMode As Range
Dim rCol As Range
Dim rMCell As Range
Dim rCell As Range
On Error GoTo ErrorHandle
Application.ScreenUpdating = False
Set rMode = Range("A1").CurrentRegion
lCols = rMode.Columns.Count - 1
Set rMode = Range(Range("B26"), Range("B26").Offset(0, lCols - 1))
For Each rMCell In rMode
lActiveCol = lActiveCol + 1
With rMCell
If .Value = "CF" Then
bCheck = False
lRedCount = 0
If IsNumeric(.Offset(1, 0).Value) And .Offset(1, 0).Value <> 0 Then
lOffset = CLng(.Offset(1, 0).Value)
If Abs(.Offset(1, 0).Value / lOffset) = 1 Then
If lOffset > 0 And lOffset + lActiveCol <= lCols Then
bCheck = True
ElseIf lOffset < 0 And lActiveCol + lOffset > 0 Then
bCheck = True
Else
MsgBox "Kolonnen med kontrolværdierer ikke i " & _
"tabellen. Tjek din offsetværdi i celle " & .Address
End If
Else
MsgBox "Kolonne-offset skal være et heltal" & _
.Offset(1, 0).Value & " ignoreres."
End If
End If
If IsEmpty(.Offset(3, 0)) = False And _
IsNumeric(.Offset(3, 0).Value) Then
dLow = .Offset(3, 0).Value
bL = True
Else
bL = False
End If
If IsEmpty(.Offset(4, 0)) = False And _
IsNumeric(.Offset(4, 0).Value) Then
dHigh = .Offset(4, 0).Value
bH = True
Else
bH = False
End If
If bL = False And bH = False Then GoTo Skip
Set rCol = Range(.Offset(-1, 0), .Offset(-24, 0))
If bL And bH Then
For Each rCell In rCol
bRed = False
With rCell
If .Value < dLow Or .Value > dHigh Then
If bCheck And .Offset(0, lOffset).Value = 1 Then
bRed = True
ElseIf bCheck = False Then bRed = True
End If
End If
If bRed Then
.Interior.ColorIndex = 3
.Interior.Pattern = xlSolid
lRedCount = lRedCount + 1
Else
.Interior.ColorIndex = xlNone
End If
End With
Next
End If
If bL And bH = False Then
For Each rCell In rCol
bRed = False
With rCell
If .Value < dLow Then
If bCheck And .Offset(0, lOffset).Value = 1 Then
bRed = True
ElseIf bCheck = False Then bRed = True
End If
End If
If bRed Then
.Interior.ColorIndex = 3
.Interior.Pattern = xlSolid
lRedCount = lRedCount + 1
Else
.Interior.ColorIndex = xlNone
End If
End With
Next
End If
If bL = False And bH Then
For Each rCell In rCol
bRed = False
With rCell
If .Value > dHigh Then
If bCheck And .Offset(0, lOffset).Value = 1 Then
bRed = True
ElseIf bCheck = False Then bRed = True
End If
End If
If bRed Then
.Interior.ColorIndex = 3
.Interior.Pattern = xlSolid
lRedCount = lRedCount + 1
Else
.Interior.ColorIndex = xlNone
End If
End With
Next
End If
Else
GoTo Skip
End If
.Offset(2, 0).Value = lRedCount
End With
Skip:
Next
BeforeExit:
Set rMode = Nothing
Set rCol = Nothing
Set rMCell = Nothing
Set rCell = Nothing
Application.ScreenUpdating = True
Exit Sub
ErrorHandle:
MsgBox Err.Description & " Procedure FormatCells"
Resume BeforeExit
End Sub
Det var det - hvordan man kan bruge VBA i stedet for Excels betingede formatering og tælle de celler, man gør noget ved.
Relateret:
|