Conditional formatting in Excel using VBA - sql

I am extremely new to VBA world and need some assistance with the VBA side of conditional formatting.
I need conditional formatting to be applied TO COLUMN (B4-B71),(D4-D71),(F4-F71),(H4-H71),(J4-J71),(L4-L71),(N4-N71),(P4-P71),(R4-R71) WHICH SATISFY a CONDITION AS BELOW.
Examplw, valid for H4 cell
=$H$4=XLOOKUP($H$4;$U$13:$U$1146;$V$13:$V$1146)THEN CHANGE TO YELLOW COLOR.
tHERE WILL BE NAMES IN THE EVERY CELL IN THE ABOVE COLUMNS AND EVERY CELL WILL CHECK THE INFORMATION IN THE COLUMN (U13-U1146).För exampl, IF THE iNFORMATIONS in cell H4 matches with the information in u column then H4 will be highlighted. the same will be applied to all the cells for above mentioned column.
and the code will be valid for apx.31 sheets in the workbook, will contain same information and same kind of conditional formatting.

Below code creates a public sub that defines the conditional formatting rules.
Function funcApplyContitionalFormatting applies the specified rules from mentioned Sub.
Public Sub condFormat(ws as Worksheet, startCol as Long, startRow as Long, fRow As Long, formattingRule as String, interiorColor as Long, fontColor as Long)
Dim rng As Range
Set rng = ws.Range(ws.Cells(startRow , startCol), ws.Cells(fRow, startCol))
rng.FormatConditions.Delete
rng.FormatConditions.Add Type:=xlExpression, Formula1:= _
formatRule
rng.FormatConditions(rng.FormatConditions.Count).SetFirstPriority
rng.FormatConditions(1).Font.Color = fontColor
rng.FormatConditions(1).Interior.Color = interiorColor
End Sub
Here are the function that applies the formatting rule above (also using a table/listobject to get the final row with data in that table):
Public Function funcApplyConditionalFormatting()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim lo As ListObject
Set lo = ws.ListObjects("yourTable")
fRow = lo.DataBodyRange.Rows.Count
Application.ScreenUpdating = False
'Call functions
condFormat(ws, 4, 3, fRow, "YourFormulaHere", 65535, 65535)
Application.ScreenUpdating = True
End Function
You'd need to change inputs to suit your specific requirements, but this works for general formatting with VBA.

Related

Maintaining destination data format when copying style in VBA?

I am trying to copy the style from a specific column (formatted as Text starting from its second row) to another column (formatted as Date starting from its second row). Both columns stores values.
I am able to copy-and-paste the style to the destination column:
.Columns("A").Copy '# "A" is the starting column
.Columns(dest_col).PasteSpecial Paste:=xlPasteFormats '# dest_col is the destination column
but this code also formats it as a Text column, while I want to keep its original formatting (i.e. Date starting from the second row).
Is there any option I can use to prevent this behavior?
You may try to take only the values of the specific parameters, which you are interested in (E.g., style, Interior Color, Font Color etc.)
The following works only when the whole column has the same format, as far as I did not to loop through every cell:
Option Explicit
Sub TestMe()
Dim colFrom As Long
Dim colTo As Long
colFrom = 1
colTo = 5
CopyFullFontAndInterior colFrom, colTo
End Sub
Sub CopyFullFontAndInterior(colFrom As Long, colTo As Long, Optional wsN As Long = 1)
Dim copyFrom As Range
Dim copyTo As Range
With Worksheets(1)
Set copyFrom = .Range(.Cells(1, colFrom), .Cells(2 ^ 20, colFrom))
Set copyTo = .Range(.Cells(1, colTo), .Cells(2 ^ 20, colTo))
End With
copyTo.Style = copyFrom.Style
If copyFrom.Interior.Color > 0 Then copyTo.Interior.Color = copyFrom.Interior.Color
If copyFrom.Font.Color > 0 Then copyTo.Font.Color = copyFrom.Font.Color
End Sub
A possible workaround is to save the format of a given cell of the column in a variable and to use it after the .PasteSpecial:
Sub TestMe()
Dim saveOurFormat As String
saveOurFormat = Columns(5).Cells(2).NumberFormat
Columns("A").Copy
Columns(5).PasteSpecial Paste:=xlPasteFormats
Columns(5).NumberFormat = saveOurFormat
Application.CutCopyMode = False
End Sub

Coloring specific cells in a column without having to change the column ref in each range variable

The code below works fine. However, I feel there must be a better way of writing it to do the job easier and quicker. Each week i have to go into VB and change the column ref in the range, so the previous week is highlighted red. Is there a way to enter the column ref once so all others are updated automatically or, even better, i can input the column ref in an input box? week1 is i, week2 is j, week3 k and so on. Thank you!
Option Explicit
Dim ws As Worksheet
Dim WSArray As Variant
Set WSArray = Sheets(Array("Baking HO", "Fresh Consol", "Moorebank", "Tamworth", "Canberra", "Fairbank", "Dandenong", "Carina", "Burleigh", "Townsville", _
"Hobart", "Forestville", "Darwin", "Malaga", "Camellia", "EP-Total", "G144 Total", "G610 Total"))
For Each ws In WSArray
ws.Range("i6:i9,i17:i18,i22:i24,i28:i34,i39:i40,i46:i49,i51:i52,i55,i59:i62,i70:i74").Interior.Color = vbRed
Next
End Sub
pass your sub a parameter to address the wanted week and use Offset() method of Range object, like follows
Option Explicit
Sub ColorPreviuosWeek(col As Long)
Dim ws As Worksheet
Dim WSArray As Variant
Set WSArray = Sheets(Array("Baking HO", "Fresh Consol", "Moorebank", "Tamworth", "Canberra", "Fairbank", "Dandenong", "Carina", "Burleigh", "Townsville", _
"Hobart", "Forestville", "Darwin", "Malaga", "Camellia", "EP-Total", "G144 Total", "G610 Total"))
For Each ws In WSArray
ws.Range("i6:i9,i17:i18,i22:i24,i28:i34,i39:i40,i46:i49,i51:i52,i55,i59:i62,i70:i74").Offset(, col - 1).Interior.Color = vbRed '<--| offset must be reduced by one so as to have offset 1 referencing column "i"
Next
End Sub
so that
ColorPreviuosWeek 2 '<-- 2 stands for "week2"
will color column "J"
Are expecting something like this.
Interactive UI for VBA-Excel

Type Mismatch 13 error when trying to activate a sheet

Everything I've read shows that I'm correctly denoting my variable and calling the sheet I want to activate. The last line is where I am getting the type mismatch. At that point CPIDws = CERN000006. I read somewhere that it might be problematic that the name is letters and numbers, but haven't found a way around it.
Sub Create_tab()
Dim newWS As Worksheet, CernWS As Worksheet, CPID As Variant
Dim Template As Worksheet, CPIDclm As Long, CERNdata As Range, CPIDcheck As Variant
Dim lngRow As Long, lngCol As Long, i As Integer, CPIDws As Worksheet
Set Template = Sheets("Template")
Set CernWS = Sheets("CERN ID's")
'Set lngRow = 1
'Set lngCol = 1
CernWS.Activate
Cells(1, 1).Select
Do
ActiveCell.Offset(1, 0).Select
Set CPID = ActiveCell
'create a new sheet as a copy of the template
Sheets("Template").Copy _
after:=ActiveWorkbook.Sheets(ThisWorkbook.Sheets.Count)
'Name the new sheet as the current CPID value from CERN ID's worksheet
ActiveSheet.Name = CPID
Set CPIDws = ActiveSheet
'interigate AAA Data and update the new sheet with the data specific to the current cpid
Sheets("AAA Data").Activate
Cells(2, 3).Activate
Set CPIDcheck = ActiveCell
Do
If CPID = CPIDcheck Then
ActiveCell.Offset(0, -2).Select
Set CERNdata = Range(Selection, Selection.End(xlToRight))
End If
Sheets(CPIDws).Activate
At that point CPIDws = CERN000006.
No it doesn't. :)
You've declared CPIDws As Worksheet but you're using it as an argument to the Sheets method, which takes either an index (integer) or name (string) value.
Thus, type mismatch.
Try simply CPIDws.Activate
or, arguably you could do the redundant: Sheets(CPIDws.Name).Activate
THIS may also come in helpful, as it's generally recommended not to rely on Active (cell, sheet, etc.) or Selection when it can be avoided (which is almost always the case, except for some instance when you use the Selection as a method of input. But generally, your macro should probably never need to Select or Activate any cell other than that which the user had selected for input. In your case, since you're beginning at Cells(1,1) and controlling the iteration entirely through code, it's not at all necessary to Select or Activate anything.

reading a range value from a cell

in the following code
Sub SetColorScheme(cht As Chart, i As Long)
Dim y_off As Long, rngColors As Range
Dim x As Long
y_off = i Mod 10
'this is the range of cells which has the colors you want to apply
Set rngColors = ThisWorkbook.Sheets("colors").Range("A1:C1").Offset(y_off, 0)
With cht.SeriesCollection(1)
'loop though the points and apply the
'corresponding fill color from the cell
For x = 1 To .Points.Count
.Points(x).Format.Fill.ForeColor.RGB = _
rngColors.Cells(x).Interior.Color
Next x
End With
End Sub
the range from which the data are read is in th emoment stated in the code. Is there a chance that it is read from asheet in the worksheet? So that a person can enter A1:C1 and it will place it the way it is in the code in the moment?
I'm not sure how you want to handle the user's input, but of course the range can be an incoming variable. I have it below as a string but elegance would be the range object. Sorry if this is too simple, I'm not sure your question.
Sub SetColorScheme(UserRange As String, cht As Chart, i As Long)
...
'this is the range of cells which has the colors you want to apply
Set rngColors = ThisWorkbook.Sheets("colors").Range(UserRange).Offset(y_off, 0)
...
End Sub
If the user enters "A1:C1" in cell D1 then you can make use of this range with:
Set rngColors = ThisWorkbook.Sheets("colors").Range(Range("D1").Value).Offset(y_off, 0)
' but you should refer to the w/sheet as well
Set rngColors = ThisWorkbook.Sheets("colors") _
.Range(ThisWorkbook.Sheets("colors").Range("D1").Value).Offset(y_off, 0)
Range("D1").Value obtains the text "A1:C1" which is then used to identify this Range.

How to compare two columns in different sheets

I have one excel file with multiple sheets.
I need to compare two sheets (1) TotalList and (2) cList with more than 25 columns, in these two sheets columns are same.
On cList the starting row is 3
On TotalList the starting row is 5
Now, I have to compare the E & F columns from cList, with TotalList E & F columns, if it is not found then add the entire row at the end of TotalList sheet and highlight with Yellow.
Public Function compare()
Dim LoopRang As Range
Dim FoundRang As Range
Dim ColNam
Dim TotRows As Long
LeaData = "Shhet2"
ConsolData = "Sheet1"
TotRows = Worksheets(LeaData).Range("D65536").End(xlUp).Row
TotRows1 = Worksheets(ConsolData).Range("D65536").End(xlUp).Row
'TotRows = ThisWorkbook.Sheets(LeaData).UsedRange.Rows.Count
ColNam = "$F$3:$F" & TotRows
ColNam1 = "$F$5:$F" & TotRows1
For Each LoopRang In Sheets(LeaData).Range(ColNam)
Set FoundRang = Sheets(ConsolData).Range(ColNam1).Find(LoopRang, lookat:=xlWhole)
For Each FoundRang In Sheets(ConsolData).Range(ColNam1)
If FoundRang & FoundRang.Offset(0, -1) <> LoopRang & LoopRang.Offset(0, -1) Then
TotRows = Worksheets(ConsolData).Range("D65536").End(xlUp).Row
ThisWorkbook.Worksheets(LeaData).Rows(LoopRang.Row).Copy ThisWorkbook.Worksheets(ConsolData).Rows(TotRows + 1)
ThisWorkbook.Worksheets(ConsolData).Rows(TotRows + 1).Interior.Color = vbYellow
GoTo NextLine
End If
Next FoundRang
NextLine:
Next LoopRang
End Function
Please help with the VBA code.
Thanks in advance...
First I am going to give some general coding hints:
set Option Explicit ON. This is done through Tools > Options >
Editor (tab) > Require Variable Declaration . Now you HAVE to
declare all variables before you use them.
always declare a variables type when you declare it. If you are unsure about what to sue or if it can take different types (not advisable!!) use Variable.
Use a standard naming convention for all your variables. Mine is a string starts with str and a double with dbl a range with r, etc.. So strTest, dblProfit and rOriginal. Also give your variables MEANINGFUL names!
Give your Excel spreadsheets meanigful names or captions (caption is what you see in excel, name is the name you can directly refer to in VBA). Avoid using the caption, but refer to the name instead, as users can change the caption easily but the name only if they open the VBA window.
Ok so here is how a comparison between two tables can be done with your code as starting point:
Option Explicit
Public Function Compare()
Dim rOriginal As Range 'row records in the lookup sheet (cList = Sheet2)
Dim rFind As Range 'row record in the target sheet (TotalList = Sheet1)
Dim rTableOriginal As Range 'row records in the lookup sheet (cList = Sheet2)
Dim rTableFind As Range 'row record in the target sheet (TotalList = Sheet1)
Dim shOriginal As Worksheet
Dim shFind As Worksheet
Dim booFound As Boolean
'Initiate all used objects and variables
Set shOriginal = ThisWorkbook.Sheets("Sheet2")
Set shFind = ThisWorkbook.Sheets("Sheet1")
Set rTableOriginal = shOriginal.Range(shOriginal.Rows(3), shOriginal.Rows(shOriginal.Rows.Count).End(xlUp))
Set rTableFind = shFind.Range(shFind.Rows(5), shFind.Rows(shFind.Rows.Count).End(xlUp))
booFound = False
For Each rOriginal In rTableOriginal.Rows
booFound = False
For Each rFind In rTableFind.Rows
'Check if the E and F column contain the same information
If rOriginal.Cells(1, 5) = rFind.Cells(1, 5) And rOriginal.Cells(1, 6) = rFind.Cells(1, 6) Then
'The record is found so we can search for the next one
booFound = True
GoTo FindNextOriginal 'Alternatively use Exit For
End If
Next rFind
'In case the code is extended I always use a boolean and an If statement to make sure we cannot
'by accident end up in this copy-paste-apply_yellow part!!
If Not booFound Then
'If not found then copy form the Original sheet ...
rOriginal.Copy
'... paste on the Find sheet and apply the Yellow interior color
With rTableFind.Rows(rTableFind.Rows.Count + 1)
.PasteSpecial
.Interior.Color = vbYellow
End With
'Extend the range so we add another record at the bottom again
Set rTableFind = shFind.Range(rTableFind, rTableFind.Rows(rTableFind.Rows.Count + 1))
End If
FindNextOriginal:
Next rOriginal
End Function