Excel - Style format on drop down list selection - excel

I'm working on a excel document being generated with APACHE POI.
The document is filled with many drop down lists for data validation.
The data chosen in those drop down lists are always of the same type:
LABEL (ID)
For the person who fills the excel document, the ID is less important than the LABEL _ but the ID is still necessary for parsing purposes.
I managed through APACHE POI to put a specific format on those kind of cells, in order to help the user to focus on the information more useful to him/her :
LABEL is in black
(ID) is in grey
My problem: when the user change a value in the cell throught the drop down list, the style format is lost on the cell.
My question: is it possible to set up a listener on my excel document that does the folowing job:
on ANY cell
filled through ANY drop down list
on ANY sheet of the workbook
set the specified cell format ?
I already have a function that does the "style format" job, but I don't know how to plug it on this kind of listener...
Function formatStyle()
Dim cellContent As String
Dim valeurLength As Integer
For Each currentCell In Selection.Cells
cellContent = currentCell.Value
For valeurLength = 1 To Len(cellContent)
If Mid(cellContent, valeurLength, 1) = "(" Then
Exit For
End If
Next valeurLength
With currentCell.Characters(Start:=1, Length:=valeurLength - 1).Font
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
End With
With currentCell.Characters(Start:=valeurLength, Length:=Len(cellContent) - valeurLength + 1).Font
.ThemeColor = xlThemeColorDark1
.Color = -4144960
End With
Next
End Function

Excel Form controls don't support any kind of font and color formatting. ActiveX controls let you change the font and colors, but not of individual characters. Custom drawing parts of the control most likely can be achieved with some complicated VBA and WinAPI calls.
The closest alternative I can think of is some of the bold extended Unicode characters:

Thanks to Determine if cell contains data validation, I've managed to do exactly what I wanted:
Private Sub Workbook_SheetChange(ByVal Sh As Object,ByVal Target As Range)
Dim cell As Range, v As Long
For Each cell In Selection.Cells
v = 0
On Error Resume Next
v = cell.SpecialCells(xlCellTypeSameValidation).Count
On Error GoTo 0
If v <> 0 Then
formatReferenceCell (Target)
End If
Next
End Sub
Function formatReferenceCell(cellContent)
Dim X As Integer
For X = 1 To Len(cellContent)
If Mid(cellContent, X, 1) = "(" Then
Exit For
End If
Next X
With ActiveCell.Characters(Start:=1, Length:=X - 1).Font
.ThemeColor = xlThemeColorLight1
.TintAndShade = 0
End With
With ActiveCell.Characters(Start:=X, Length:=Len(cellContent) - X + 1).Font
.ThemeColor = xlThemeColorDark1
.Color = -4144960
End With
End Function

Related

Duplicate a conditional macro to the next row xxx

I'd like to find the way to duplicate this at the following rows. It has to go from C1:E1 than C2:E2 and so on.
Sub Conditional()
Conditional Macro
Range("C1:E1").Select
Selection.FormatConditions.AddUniqueValues
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
Selection.FormatConditions(1).DupeUnique = xlUnique
With Selection.FormatConditions(1).Font
Color = -16383844
TintAndShade = 0
End With
With Selection.FormatConditions(1).Interior
PatternColorIndex = xlAutomatic
Color = 13551615
TintAndShade = 0
End With
Selection.FormatConditions(1).StopIfTrue = False
End Sub
I am very new to excel
Thanks in advance
Recommendations
Selects should be replaced; not addressing for color handling in the solution, but you may consider to change to a RGB logic since themes may vary per user and the color may not be the one that you originally intended to. I will think that you need it in 2 different rulings as now (the duplicates in each column and not in the range).
Solution
Sub Exec_Conditional()
Call Conditional(Range("C1:E1"))
Call Conditional(Range("C2:E2"))
End Sub
Sub Conditional(RangeToPerform As Range)
'if you need to have this condition only in the range, otherwise comment the delete line
RangeToPerform.FormatConditions.Delete
RangeToPerform.FormatConditions.AddUniqueValues
RangeToPerform.FormatConditions(RangeToPerform.FormatConditions.Count).SetFirstPriority: RangeToPerform.FormatConditions(1).DupeUnique = xlUnique
With RangeToPerform.FormatConditions(1).Font
.Color = -16383844: .TintAndShade = 0
End With
With RangeToPerform.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic: .Color = 13551615: .TintAndShade = 0
End With
RangeToPerform.FormatConditions(1).StopIfTrue = False
End Sub

Use xlExpression with "And" in conditional format

I'm trying to use VBA to give conditional formatting to my table, however my code generates error.
The code is:
Range("M236:P240").Select
Selection.FormatConditions.Add Type:=xlExpression, _
Formula1:="=AND(<$M$241, <7)"
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Font
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
End With
With Selection.FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 192
.TintAndShade = 0
End With
When I run it I get an error 5 in the line:
Formula1:="=AND(<$M$241,<7)"
I think it must be a small mistake, maybe I'm missing some parentheses or some quotation marks.
Why is this error generated?
PD: If I change it for:
Formula1:="=AND(M236<$M$241; M236<7)"
The code run, but nothing happens.
I Solved the problem. I had several errors which I mention below:
Thanks to #Scott Craner who mentioned that the formula should not be Formula1:="=AND(<$M$241, <7)" but (M236<$M$241; M236<7)
Secondly my excel for formulas does not use "," but ";".
My excel is in Spanish, so I shouldn't use "AND" but "Y".
try this macro
Option Explicit
Sub colorize_me()
Dim Rg_To_compaire As Range
Dim My_Rg As Range
Dim Single_Range As Range
Dim My_const As Byte: My_const = 7
Set Rg_To_compaire = Range("M241")
Dim My_min#
My_min = Application.Min(Rg_To_compaire, My_const)
If Not IsNumeric(Rg_To_compaire) Then Exit Sub
Set My_Rg = Range("M236:P240")
For Each Single_Range In My_Rg
If IsNumeric(Single_Range) And Single_Range < My_min Then
Single_Range.Interior.ColorIndex = 6
Else
Single_Range.Interior.ColorIndex = xlNone
End If
Next
End Sub

How to write VBA for Do Until last row of data set

I am new to VBA and looking to run a code to colour cells in rows in a specific colour. I have been using DO UNTIL and always end with an extra cell coloured. What is the best way to overcome this.
The table I am working with looks like this,
Number/Name
1/test_01
2/test_02
3/test_03
4/test_04
5/test_05
and continues on and the end will change each time i run the code.
I have set up a test sheet to get the basic idea running so I can expand upon it once I have it running properly. This specific test is dividing column A (Number) by 2 and if there is a remainder of 1 then it will be coloured one way and if not it will be coloured another.
Sub Button2_Click()
Dim row_cnt As Integer
row_cnt = 1
Do Until Sheets("sheet1").Range("A" & row_cnt).Value = ""
row_cnt = row_cnt + 1
If Sheets("sheet1").Range("A" & row_cnt).Value Mod 2 <> 0 Then
Range("A" & row_cnt & ":B" & row_cnt).Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent6
.TintAndShade = -0.249977111117893
.PatternTintAndShade = 0
End With
Else
Range("A" & row_cnt & ":B" & row_cnt).Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorAccent4
.TintAndShade = -0.249977111117893
.PatternTintAndShade = 0
End With
End If
Loop
End Sub
I expect the cells to be coloured until the last cell with a value in. However, this code goes past that and colours an extra cell. I am looking for a way to improve what I have.
you can dynamically find the last row, such that:
lr = cells(rows.count,1).end(xlup).row
row_cnt = 1
Do until row_cnt = lr+1 'so you get actions on your last row
'do stuff
row_cnt = row_cnt + 1
loop
if you can avoid vba for this, bigben's suggestion for conditional formatting would be solid
To answer the specific Q "Why doesn't my Do Untilwork":
It's because you test based on a value of row_cnt , then immediately increment it inside the loop, so process the next row.
To fix that, move the increment to just before Loop and adjust the initialisation of row_cnt
On a side note, you should use Long rather than Integer as the counter data type

Conditional Formatting with Reference Formula

I am working on code that uses Excel buttons to run code. The purpose of this code is to insert a formatted line so that a technical can fill out data values as needed. This way the technician can keep adding as many lines as need.
For one of the test that the technician is performing I want the value to be conditional formatted grey if it is below a certain threshold. The issue with this is that because I keep inserting cell lines into excel I can not reference the same location. I placed buttons to insert these lines and I am using the button location as a reference. Is there any way to use FormulaR1C1 or a different method to make this happen?
My code looks like this:
Private Sub CommandButton2_Click()
Dim V_Val As Variant ' Make the voltage value a variable
Dim rs As Integer ' The push button location
Dim cs As Integer
V_Val = InputBox("Voltage Above") ' Ask user input
rs = ActiveSheet.Shapes("CommandButton2").TopLeftCell.Row ' Get push button location
cs = ActiveSheet.Shapes("CommandButton2").TopLeftCell.Column
Worksheets("Format3").Rows("7:7").Copy 'Always grab from the same location
Worksheets("Meas_sum").Rows(rs).Insert Shift:=xlDown
ActiveSheet.Cells(rs, cs + 1).Select ' Place the voltage value in
Selection.NumberFormat = "#"
Selection.Value = V_Val
' Sig Pulse Grey out code
Range(Cells(rs, cs + 16), Cells(rs, cs + 29)).Select
Selection.FormatConditions.Add Type:=xlExpression, _
ActiveSheet.Cells(r2 + 2, c2 + i).FormulaR1C1 = "=R[-1]C/R[-2]C"
'Formula1:="=G6*1.5>Q6" 'Make above work from refference value
Selection.FormatConditions(Selection.FormatConditions.Count).SetFirstPriority
With Selection.FormatConditions(1).Font
.ThemeColor = xlThemeColorDark1
.TintAndShade = -0.499984740745262
End With

Changing cell values based on table headers and a single column

I'm trying to turn certain cells red based on information from a single row and column. What my algorithm is supposed to do is search through the single column and find a matching string and save that the column number, then do the same for the row. Then the script selects the cell and turns it red.
All the keys that I search for come from a piece of code that I found online and modified to suit my needs. It works perfectly. The problem is I can't get the search to work properly.
Option Explicit
Sub Blahbot()
Dim xRow As Long
Dim x As Long, y As Long
Dim xDirect$, xFname$, InitialFoldr$, xFF$
InitialFoldr$ = "G:\" '<<< Startup folder to begin searching from
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = Application.DefaultFilePath & "\"
.Title = "Please select a folder to list Files from"
.InitialFileName = InitialFoldr$
.Show
If .SelectedItems.Count <> 0 Then
xDirect$ = .SelectedItems(1) & "\"
xFname$ = Dir(xDirect$, 7) '<<< Where the search terms come from
Do While xFname$ <> ""
y = Application.WorksheetFunction.Match(Mid(xFname$, 11, 4), Range("D2:KD2"), 0) '<<< Find a matching string in table header
x = Application.WorksheetFunction.Match(Mid(xFname$, 16, 4), Range("B3:B141"), 0) '<<< Find matching string in column B
Cells(x, y).Select '<<<Select the cell and turn it red
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 255
.TintAndShade = 0
.PatternTintAndShade = 0
End With
xFname$ = Dir
Loop
End If
End With
End Sub
What the code does is that it reads through a folder, gets the file names, and splits them up. The name will always be ####_#### (where #=upper case letter and #### is a time in 24-hour format).
The Mid function splits that name up into the 4 letters and the time.
If you understand what I'm trying to do, could you suggest a better search algorithm or see what my code is doing wrong?
I simplified my answer because I may have misunderstood your question. MATCH returns a value relative to the range you look in. So if the match is in Column D, then MATCH returns 1. Therefore, you'll need to offset the returned value.
'Add 2 to x, since we start on 3rd row, add 3 to y since we start on 4th column
Cells(x+2, y+3).Select
You may also want to include code to check if there is no match. To see if you're having this issue, you can use the code below to test for this or add watches.
On Error Resume Next
y = Application.WorksheetFunction.Match(...)
If Err = 0 Then
MsgBox "All is well"
Else
MsgBox "There was an error with Match"
End If
On Error Goto 0

Resources