Group of cells background colouring using VBA

csbaros

New Member
Joined
Apr 22, 2021
Messages
25
Office Version
  1. 2016
Platform
  1. Windows
Dear Folks,

Please help me to fix the vba code. My intention would be the following:

There is two type of units on the sample bordered thicker line: 3x27 cells or 3x9 cells

1. I can switch with the selector in the second row from values 0F, 1F, 2F, 3F, 4F or 0S, 1S, 2S, 3S, 4S and it change the color of the units (it works already):
(I always use the dropdown(data validation) menu for selector)

1.jpg


2. In the second cell of top and bottom row of big units (first at small units), in the selector could be switched empty and full circles in the top and bottom rows. (it works already)

But this function have to work only when the previous switch (second row selector) in 0F or 0S. At setting 1F,2F,3F,4F,1S,2S,3S,4S circles have to stay stay unchanged.

2.jpg


3. But if I'm in 1F,2F,3F,4F,1S,2S,3S,4S mode in the second row selector and I change between circles in the first and third row selector, the code stop to work with error

3.jpg


4. I would like if the code work as: It have to be possible to switch between empty and full circles (with selector button in the top and bottom row), when the second row selector is only in 0F or 0S value. If the second row selector on the other values, then changing the circle selector have to be ineffective.

I hope someone could help me

Please download the sample sheet from here:

I would clarify it again, if I'm blurry.

Thank you very much

Csaba
 

Excel Facts

How can you automate Excel?
Press Alt+F11 from Windows Excel to open the Visual Basic for Applications (VBA) editor.
Hi @csbaros, your project aroused my curiosity. I've read through some previous threads and built a workbook from scratch.
You won't recognize much of the existing code anymore, I chose a slightly different approach.

The workbook needs three worksheets, one as a canvas for your plot, a second with some tables used for the data validation dropdowns, and a third with some "prefab" elements, from which copies are placed onto the canvas by code. A confirmation is requested after each plotted element. This offers the possibility to reverse the last action in case the element to be plotted ended up in the wrong place on the canvas. This reduces the chance of having to manually restore the layout worksheet.

The Worksheet_Change event handler is used to track the changes caused by the dropdowns:
- colorize the element when changing the code;
- allow both marker dropdowns only when code 0F or 0S is entered (the first code of each of the two code tables);
- remove these marker dropdowns when any other code is entered.

Each element type has its own plot macro. On pressing Alt F8 those (currently four) macros are shown in a dialog and can be run from there.

I've dropped an example workbook over here (Example) along with a small video on how those data validation tables were made, as far as needed. The video was made in the very first steps of the process and no longer reflects the current situation of the workbook. The prefab templates only contain a validation dropdown for the code. The dropdowns for the markers may or may not be placed after the templates are plotted, depending on user interaction. However, the video does give a clear picture of the steps to follow if you want to make extensions yourself.


ScreenShot209.jpg


ScreenShot210.jpg



This goes in the module of worksheet Layout:
VBA Code:
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
    RespondOnLayoutChange Target
End Sub

This goes in a standard module:
VBA Code:
Option Explicit

Public Sub PlotFullOne()
    PlotTemplate "FullOne"
End Sub
Public Sub PlotFullTwo()
    PlotTemplate "FullTwo"
End Sub
Public Sub PlotSmallOne()
    PlotTemplate "SmallOne"
End Sub
Public Sub PlotSmallTwo()
    PlotTemplate "SmallTwo"
End Sub

Public Sub PlotTemplate(ByVal argTemplateName As String)

    Const PH                As String = "@#$@"
    Const ERROR_MSG         As String = "Template with name [" & PH & "] is not present or is not recognized."

    Const PLOT_ROWCOUNT     As Long = 5
    Const PLOT_ROWHEIGHT    As Long = 9
    Const TEMPL_FULLWIDTH   As Long = 27
    Const TEMPL_SMALLWIDTH  As Long = 9
    Const TEMPLATE_OFFSET   As Long = 3          ' = column D
    Const UNDO_OFFSET       As Long = 33         ' = column AH

    Dim wsSource  As Worksheet, wsDest As Worksheet
    Dim arrRows() As Variant
    Dim d As Range, r As Range, c As Range
    Dim n As Long, i As Long

    Set wsDest = ThisWorkbook.Worksheets("Layout")

    ' only allow plotting if sheet for which this procedure is intended is on screen
    ' otherwise the provided Accept / Undo dialog makes no sense
    
    If ActiveSheet.Name = wsDest.Name Then

        Set d = ActiveCell
        If Not argTemplateName = vbNullString Then

            Set wsSource = ThisWorkbook.Worksheets("Templates")

            With wsSource
                ' range with template names
                Set r = .Range("A4:A" & .Cells(.Rows.Count, "A").End(xlUp).Row)
            End With
            ' look for given template
            Set c = r.Find(argTemplateName, , , xlWhole)
            If Not c Is Nothing Then

                If Left(argTemplateName, 1) = "F" Then
                    ' set amount of culumns
                    n = TEMPL_FULLWIDTH

                ElseIf Left(argTemplateName, 1) = "S" Then
                    ' set amount of culumns
                    n = TEMPL_SMALLWIDTH
                Else
                    ' unknown prefix = unknown dimension > inform user and quit
                    MsgBox Replace(ERROR_MSG, PH, argTemplateName), vbExclamation, "Plot template"
                    Exit Sub
                End If

                ' from this point on, interruptions caused by Excel events are unwanted
                ' our dropdowns don't have to be monitored for a while so any (custom) event handler can be disabled safely
                Application.EnableEvents = False
                    
                ' store content of destination area, providing an undo possibility
                With d.Resize(PLOT_ROWCOUNT, n)
                    .Copy Destination:=c.Offset(0, UNDO_OFFSET)
                    ' store height of each row involved
                    ReDim arrRows(PLOT_ROWCOUNT)
                    For i = 1 To PLOT_ROWCOUNT
                        arrRows(i) = .Cells(i, 1).EntireRow.Height
                    Next i
                End With

                ' plot template in Layout sheet
                c.Offset(0, TEMPLATE_OFFSET).Resize(PLOT_ROWCOUNT, n).Copy Destination:=d
                ' adjust row height
                d.Resize(PLOT_ROWCOUNT, n).Rows.RowHeight = PLOT_ROWHEIGHT
                
                With c.Offset(0, UNDO_OFFSET).Resize(PLOT_ROWCOUNT, n)
                    If vbNo = MsgBox("Plotted as intended?", vbQuestion + vbYesNo, "Plot template") Then
                        ' perform an Undo
                        .Copy Destination:=d
                        ' restore row heights
                        With d.Resize(PLOT_ROWCOUNT, n)
                            For i = 1 To PLOT_ROWCOUNT
                                .Cells(i, 1).EntireRow.RowHeight = arrRows(i)
                            Next i
                        End With
                    End If
                    ' clear undo storage
                    .ClearContents
                    .ClearFormats
                End With
                
                ' enable all event handlers (and monitor our dropdowns again)
                Application.EnableEvents = True

            Else
                ' unknown Template Name > inform user and quit
                MsgBox Replace(ERROR_MSG, PH, argTemplateName), vbExclamation, "Plot template"
            End If
        Else
            ' given Template Name appears to be an empty string ("") > inform user and quit
            MsgBox Replace(ERROR_MSG, PH, argTemplateName), vbExclamation, "Plot template"
        End If
    Else
        ' wrong worksheet on screen > do nothing
    End If
End Sub


Public Sub RespondOnLayoutChange(ByVal Target As Range)

    ' these constants hold Named Ranges > used as lists within the validation dropdowns

    Const FULL_MARKERS  As String = "DD_MarkersF"
    Const SMALL_MARKERS As String = "DD_MarkersS"
    Const FULL_CODES    As String = "DD_CodesF"
    Const SMALL_CODES   As String = "DD_CodesS"
    Const EXT_CODES_C   As String = "DD_CodesExtC"
    Const EXT_CODES_S   As String = "DD_CodesExtS"

    Dim rng As Range, arr As Variant
    Dim dvt As XlDVType, dvf As String
    Dim ErrNr As Long, i As Long, clr As Long

    ' ignore change events from multiple cells at once
    If Not Target.CountLarge > 1 Then

        ' is the data input in the changed cell limited by data validation?
        On Error Resume Next
        dvt = Target.Validation.Type
        ErrNr = Err.Number
        On Error GoTo 0
        If ErrNr = 0 Then

            ' validation detected, proceed
            If dvt = xlValidateList Then

                ' we are about to make changes to a worksheet while this code is invoked when that particular worksheet changes
                ' we therefore need to disable any event handler to prevent endless recursive behaviour
                Application.EnableEvents = False

                ' obtain involved list
                dvf = Target.Validation.Formula1

                ' check whether a specific plotted element is involved
                If StrComp(dvf, "=" & FULL_CODES, vbTextCompare) = 0 Then
                    Set rng = Application.Union(Target.Offset(-1, 1), Target.Offset(1, 1))
                    MarkersDropDown Target.Value, rng, FULL_CODES, FULL_MARKERS
                    Target.Offset(-1, 0).Resize(3, 27).Interior.Color = GetColor(Target, FULL_CODES)

                ElseIf StrComp(dvf, "=" & SMALL_CODES, vbTextCompare) = 0 Then
                    Set rng = Application.Union(Target.Offset(-1, 0), Target.Offset(1, 0))
                    MarkersDropDown Target.Value, rng, SMALL_CODES, SMALL_MARKERS
                    Target.Offset(-1, 0).Resize(3, 9).Interior.Color = GetColor(Target, SMALL_CODES)

                ElseIf StrComp(dvf, "=" & FULL_MARKERS, vbTextCompare) = 0 Then
                    arr = Array(2, 4, 6, 9, 11, 13, 15, 18, 20, 22, 24)
                    CombineNotContiguousCellsOnSameRow(Target, arr).Value = Target.Value

                ElseIf StrComp(dvf, "=" & SMALL_MARKERS, vbTextCompare) = 0 Then
                    arr = Array(2, 4, 6, 8)
                    CombineNotContiguousCellsOnSameRow(Target, arr).Value = Target.Value

                ElseIf StrComp(dvf, "=" & EXT_CODES_C, vbTextCompare) = 0 Then
                    i = Application.Evaluate("=MATCH(""" & Target.Value & """," & EXT_CODES_C & ", 0)")
                    Target.Interior.Color = Range(EXT_CODES_C).Cells(i, 1).Offset(0, 1).Interior.Color

                ElseIf StrComp(dvf, "=" & EXT_CODES_S, vbTextCompare) = 0 Then
                    i = Application.Evaluate("=MATCH(""" & Target.Value & """," & EXT_CODES_S & ", 0)")
                    Target.Interior.Color = Range(EXT_CODES_S).Cells(i, 1).Offset(0, 1).Interior.Color

                Else
                    ' no plotted element involved > do nothing
                End If

                ' we are done, enable all (custom) event handlers
                Application.EnableEvents = True
            Else
                ' data validation detected, but of the wrong type > do nothing
            End If
        Else
            ' no data validation detected > do nothing
        End If
    Else
        ' multiple cells have been changed at the same time > do nothing
    End If
End Sub

Private Function CombineNotContiguousCellsOnSameRow(ByVal Target As Range, ByVal OffsetsArray As Variant) As Range
    Dim r As Range, n As Variant
    For Each n In OffsetsArray
        If r Is Nothing Then
            Set r = Target.Offset(0, n)
        Else
            Set r = Application.Union(r, Target.Offset(0, n))
        End If
    Next n
    Set CombineNotContiguousCellsOnSameRow = r
End Function

Private Sub MarkersDropDown(ByVal argCondition As String, ByVal argDropDownRange As Range, ByVal argCODES As String, argMARKERS As String)
    If argCondition = Range(argCODES).Cells(1, 1).Value Then
        SetValidationAllowList argDropDownRange, argMARKERS
    Else
        argDropDownRange.Validation.Delete
    End If
End Sub

Private Function GetColor(ByVal Target As Range, ByVal argCODES As String) As Long
    Dim i As Long
    i = Application.Evaluate("=MATCH(""" & Target.Value & """," & argCODES & ", 0)")
    GetColor = Range(argCODES).Cells(i, 1).Offset(0, 1).Interior.Color
End Function

Private Sub SetValidationAllowList(ByVal argRng As Range, ByVal argNameOfList As String)
    Dim nm As Name
    If Not argRng Is Nothing Then
        With argRng.Validation
            .Delete
            .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:="=" & argNameOfList
            .IgnoreBlank = True
            .InCellDropdown = True
            .InputTitle = ""
            .ErrorTitle = ""
            .InputMessage = ""
            .ErrorMessage = ""
            .ShowInput = True
            .ShowError = True
        End With
    End If
End Sub
 
Upvote 0
Solution
Dear @GWteB

First of all, I don't know how to express my appreciation to you, because of your great help.

I've started to learn your material, but I will need more time on the weekend dig into myself deeper.

Please allow me to give you a feedback at latest on Monday.

Thank you so much, really appreciate it

Kind regards

Csaba

 
Upvote 0
My pleasure! I like the challenge to tinker with applications that actually have nothing to do with Excel's main function (calculations), it was a nice project to work on.
Take your time, I'll keep watching ...
 
Upvote 0
Dear @GWteB,

Sorry, that I couldn't keep my promise regarding Monday ... I'm living in very busy days ...
I checked your modifications and the functions are working properly. I will test it more deeply and I will carry through these modifications to the whole site layout, which are ca.1200 Full unit and 200 Small unit. Then I'll see in the next 1-2 month how it'll work.

May I kindly ask your help later on, if I'll bump into some difficulties regarding this project ?

I would like to express my appreciation to you again for your effort

Thanks a lot

Csaba
 
Upvote 0
Sorry, that I couldn't keep my promise regarding Monday ...
Hey Csaba, don't worry about that ... as I said, my pleasure.
Btw, this forum has a lot of members who frequently and effectively answer questions from other members, so don't hesitate to ask around and feel free to post your questions.
And out of interest I'll keep watching this thread.
 
Upvote 0

Forum statistics

Threads
1,214,877
Messages
6,122,051
Members
449,064
Latest member
scottdog129

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top