Search code examples
excelvbaloopsborder

How to cycle through borders in Excel and change their color?


I am trying to cycle through active borders in Excel and to change their colors to "next one".

Here is the code I have:

Dim Color1 As Variant
Dim Color2 As Variant
Dim Color3 As Variant
Dim Color4 As Variant
Dim Color5 As Variant

Color_default = RGB(0, 0, 0)
Color1 = RGB(255, 0, 0)
Color2 = RGB(0, 255, 0)
Color3 = RGB(0, 0, 255)
Color4 = RGB(222, 111, 155)
Color5 = RGB(111, 111, 111)

Dim cell As Range
Dim positions As Variant
Dim i As Integer

positions = Array(xlDiagonalDown, xlDiagonalDown, xlEdgeLeft, xlEdgeTop, xlEdgeBottom, xlEdgeRight, xlInsideVertical, xlInsideHorizontal)

For Each cell In Selection
    For i = LBound(positions) To UBound(positions)
        If cell.BORDERS(positions(i)).LineStyle <> xlNone Then
            If cell.BORDERS(positions(i)).Color = Color_default Then
                cell.BORDERS(positions(i)).Color = Color1
            ElseIf cell.BORDERS(positions(i)).Color = Color1 Then
                cell.BORDERS(positions(i)).Color = Color2
            ElseIf cell.BORDERS(positions(i)).Color = Color2 Then
                cell.BORDERS(positions(i)).Color = Color3
            ElseIf cell.BORDERS(positions(i)).Color = Color3 Then
                cell.BORDERS(positions(i)).Color = Color4
            ElseIf cell.BORDERS(positions(i)).Color = Color4 Then
                cell.BORDERS(positions(i)).Color = Color5
            Else
                cell.BORDERS(positions(i)).Color = Color_default
            End If
        End If
    Next i
Next cell

It works. It does not change the weight of the borders and it does not add new borders (only changes the existing ones).

The issue is that when two cells are nearby, the outer borders are changes to "next+1" color, and the inner borders are changed to "next+2" color, as they are looped through two times.

EDIT: The code should check if the existing border colors are the ones I want to use. Secondly, the colors should be unified first, to avoid multiple border colors within selection.

A picture of the problem
enter image description here

I want to unify the borders and then be able to cycle through their colors, regardless what their weight is and without adding NEW borders.


Solution

  • This code should do what you want. It reads the existing color from a framed cell within the selection, determines which is the next color to set and sets all colours accordingly.

    Sub CycleBorderColors(Optional ByVal Reset As Boolean)
    
        Dim BorderColor As Variant
        Dim BorderPos As Variant
        Dim CurrentColor As Long
        Dim ColorIndex As Long
        Dim Cell As Range
        Dim i As Integer
    
    
        BorderPos = Array(xlDiagonalDown, xlDiagonalUp, xlEdgeLeft, xlEdgeTop, _
                          xlEdgeBottom, xlEdgeRight, xlInsideVertical, xlInsideHorizontal)
        BorderColor = Array(RGB(0, 0, 0), RGB(255, 0, 0), RGB(0, 255, 0), _
                            RGB(222, 111, 155), RGB(111, 111, 111))
    
        If Reset Then
            ColorIndex = Reset
        Else
            CurrentColor = xlNone
            ' read the border color of the first selected cell with a border
            For Each Cell In Selection.Cells
                For i = LBound(BorderPos) To UBound(BorderPos)
                    With Cell
                        If .Borders(BorderPos(i)).LineStyle <> xlNone Then
                            CurrentColor = .Borders(BorderPos(i)).Color
                            Exit For
                        End If
                    End With
                Next i
                If CurrentColor <> xlNone Then Exit For
            Next Cell
            If CurrentColor = xlNone Then
                MsgBox "The selection includes no cells with borders.", _
                       vbInformation, "Inapplicable selection"
                Exit Sub
            End If
    
            For ColorIndex = UBound(BorderColor) To 0 Step -1
                If BorderColor(ColorIndex) = CurrentColor Then Exit For
            Next ColorIndex
            ' ColorIndex will be -1 if not found
        End If
        ColorIndex = ColorIndex + 1                 ' set next color
        If ColorIndex > UBound(BorderColor) Then ColorIndex = 0
    
        For Each Cell In Selection
            For i = LBound(BorderPos) To UBound(BorderPos)
                If Cell.Borders(BorderPos(i)).LineStyle <> xlNone Then
                    Cell.Borders(BorderPos(i)).Color = BorderColor(ColorIndex)
                End If
            Next i
        Next Cell
    End Sub
    

    The procedure has an optional argument which, if set to True, causes a reset. The current program sets the border color to default. In hindsight the idea isn't so hot because you could cause a reset by running the code 4 or fewer times. But when I started it seemed like a good idea. Now you may prefer to remove the feature. The easiest way would be to remove the argument from the declaration, add Dim Reset As Boolean to the variable declarations and leave the rest to itself.

    While you do have the the option to reset use an intermediary to call the procedure. Any of the three variants shown below will work.

    Sub CallCycleBorderColors()
        CycleBorderColors
      ' CycleBorderColors True
      ' CycleBorderColors False
    End Sub
    

    Call the sub CallCycleBorderColors from the worksheet.