Related
I have a userform display that is Dynamic and updates itself as I enter in information on a separate worksheet.
What I would like it to do, is set forecolor to red for any negative values that occur under the Deadlift section. I have tried using this code and a few others, but, so far, I do not get errors, nor do I get the font to change color
Sub updateForm2()
Dim lLoop As Long
For lLoop = 163 To 312
If myForm.Controls("Label" & lLoop).Value < 0 Then
myForm.Controls("Label" & lLoop).ForeColor = RGB(255, 0, 0)
Else
myForm.Controls("Label" & lLoop).ForeColor = RGB(0, 0, 0)
End If
Next
End Sub
I have an updateForm, that dynamically updates all the labels as positions change based on the amount lifted
Sub updateForm()
Dim wks As Worksheet
Set wks = Sheets("DeadGenerator")
'Update label values here
myForm.Label1.Caption = wks.Range("c4").Text
myForm.Label2.Caption = wks.Range("c5").Text
to
myForm.Label162.Caption = wks.Range("f41").Text
Then labels
myForm.Label163.Caption = wks.Range("g12").Value
to
myForm.Label312.Caption = wks.Range("k41").Value
are the labels that correspond to the 5 columns under the Deadlift Heading
Any help is appreciated, I am still very new to using Userforms
Thanks
Hope this Help. I replied your form in a really easy way. Just added 3 Labels and linked the caption to cells A1,B1 and C1 (those values are 0,-1,-2).
Ok, First of all, to make this work, you must select ALL the labels you want to have the chance of getting a red backcolor. Then, once you have selected all, use the property TAG (read more here)(in my example, I selected just Label2 and Label3 tho have this chance of red backcolor. Label1 will never ever be red even if caption is below 0). Tag value must be "RedOne" (or adapt the code and tag value to your needs)
Ok, now the code. This code will check EVERY control in your userform. And then, if the TAG value is "RedOne" it will check the caption. And if the caption is below 0, then it will make the backcolor red.
Dim MyLabel As control
For Each MyLabel In Me.Controls
If MyLabel.Tag = "RedOne" Then
If MyLabel.Caption < 0 Then
MyLabel.BackColor = vbRed
Else
MyLabel.BackColor = vbWhite
End If
End If
Next MyLabel
And now, let's test it. Note that only label2 and 3 are red because values are both below 0.
Let's test it with Label1.Caption below 0 also. But Label1.Tag is blank, so backcolor will remain the sam, even with values below 0.
And last test. Let's make Label2 value below 0, but label3 value is over 0. Now, only Label2 gets red backcolor, because it's the only label that meets both conditions (Tag="RedOne" and Value<0).
Hope this helps, and I hope you can adapt it to your needs.
Just 1 advice. To set the Tag value, just select ALL the labels you want (Labels under deadlift section) and then type the Tag Value. You don't need to select one by one and type the Tag value one by one.
Let me know if this worked.
Excel uses black by default for the Font Color on the tabs. When you change the tab color, the Font Color remains black if the tab color is light, but changes to white when a darker color is chosen.
I would like to mimic this behavior. For which RGB combinations does Excel change to white Font Color?
Many thanks!
The possible colors of the tab are 256^3. Try it out for yourself:
Public Sub TestMe()
Dim cnt As Long
For cnt = 1 To 256 ^ 3 Step 10
ActiveSheet.Tab.Color = cnt
Next cnt
End Sub
I have followed the approach suggested by #Vityata. Excel behavior is not straight forward to replicate, but I have found an approximation that serve my purposes:
Considering the color cube as in:
http://matlab.izmiran.ru/help/toolbox/images/colorcube.jpg
Excel approximately uses white Font color when
R * 20132 + G * 64005 + B * 6630 <= 11675430
This will fail in some edge cases (eg: RGB(255,102,3)), but I still hope someone finds this useful. I am leaving the question open in case anyone founds an exact formula.
Thanks for the replies.
I have written a piece of code that allows me to retrieve the shading color of a specific cell inside a sheet of an excel workbook. I have successfully retrieved the RGB integer value by starting a COM server using MATLAB's actxserver, and then accessing the Color Property of the Interior Object of that particular Cell Object. Then I obtain the equivalent RGB triplet of that integer, so I can use it later for plotting in MATLAB.
In order to test that my code works properly I designed the following test: I created an Excel workbook called colorTest.xlsx with 8 different colors:
Then I run my MATLAB code, which extracts the color information on each cell of the B column. I should get a plot with the colors on the same vertical order and a table with the int value and the RGB triplet of each color.
However something unexpected happens! Look at the results:
Notice that the integer value that is obtained from the Color Property does not always match the color of the original cell, for black, white, green and magenta the integer values are correct, but this is not true for all the other colors. You can see, for example, that for red color on the Excel, the output int and RGB triplet correspond to blue color.
I have added the following table with the correct results I should get, for reference:
Color Int R G B
-------- -------- -----
Black 0 0 0 0
White 16777215 1 1 1
Red 16711680 1 0 0
Green 65280 0 1 0
Blue 255 0 0 1
Cyan 65535 0 1 1
Magenta 16711935 1 0 1
Yellow 16776960 1 1 0
I obtained the correct integer values for each color using this RGB Int Calculator.
If we compare the two tables, we can deduce that the Red and Blue channels are inverted.
The code:
The function that I execute to run the test is called getCellColor. Have a look at the code:
function getCellColor()
clear all;
clc;
% Excel
filename = 'colorTest.xlsx';
% Start Excel as ActiveX server process on local host
Excel = actxserver('Excel.Application');
% Handle requested Excel workbook filename
path = validpath(filename);
% Cleanup tasks upon function completion
cleanUp = onCleanup(#()xlsCleanup(Excel, path));
% Open Excel workbook.
readOnly = true;
[~, workbookHandle] = openExcelWorkbook (Excel, path, readOnly);
% Initialise worksheets object
workSheets = workbookHandle.Worksheets;
% Get the sheet object (sheet #1)
sheet = get(workSheets,'item',1);
% Print table headers
fprintf('Color \t Int \t R G B\n');
fprintf('--------\t --------\t -----\n');
% Create figure
figure;
hold on;
% Loop through every color on the Excel file
for row = 1:8
% Get the cell object with name of color
cell = get(sheet, 'Cells', row, 1);
cName = cell.value;
% Get the cell object with colored background
cell = get(sheet, 'Cells', row, 2);
% Get the interior object
interior = cell.Interior;
% Get the color integer property
cInt = get(interior, 'Color'); % <-- Pay special attention here(*)
% Get the RGB triplet from its integer value
cRGB = int2rgb(cInt);
% Plot the color
patch([0 0 1 1], [8-row 9-row 9-row 8-row], cRGB);
% Print row with color data
fprintf('%-8s\t %8d\t %d %d %d\n', cName, cInt, cRGB);
end
% Turn off axes
set(findobj(gcf, 'type','axes'), 'Visible','off')
end
(*) This instruction is responsible of recovering the color integer.
Note: The functions described next, do not cause the problem since they do not take part in the obtaining of the color integer (they are only used for secondary tasks). I have included this information only for completeness.
During this process I use three private functions from the MATLAB's iofun folder, which are: validpath, xlsCleanup and openExcelWorkbook. I simply copied them into a folder called private inside the project folder.
Finally, to obtain the RGB triplet from the color integer, I use a function which I adapted from this other function that I found on the net.
Here is the code for my int2rgb function:
function[RGB] = int2rgb(colorInt)
% Returns RGB triplet of an RGB integer.
if colorInt > 16777215 || colorInt < 0
error ('Invalid int value. Valid range: 0 <= value <= 16777215')
end
R = floor(colorInt / (256*256));
G = floor((colorInt - R*256*256)/256);
B = colorInt - R*256*256 - G*256;
RGB = [R, G, B]/255;
end
I am trying to make some sense out of this, but I really have no idea of what is happening. I have done some research, without much luck, but this post and this other post caught my attention. Maybe it has something to do with my problem.
So does the Interior.Color Property really inverts colors?
If this is the case, should I consider this as normal behavior or is this a bug?
Link to download:
I have packed the entire project on a .zip file and uploaded it, so you can run this test on your machine straight away. Download the file and unpack.
getCellColor.zip
There is no "right" or "wrong" here, Matlab and Excel just encode color differently. You need to account for that in your code.
The closest I can find to an official source is this MSDN article, about half way down see the example of encoding of "blue"
MSDN article
The following examples set the interior of a selection of cells to the color blue.
Selection.Interior.Color = 16711680
Selection.Interior.Color = &HFF0000
Selection.Interior.Color = &O77600000
Selection.Interior.Color = RGB(0, 0, 255)
My first thought is check the channels order RGB vs. BGR.
You could probably simplify that int2rgb function by using typecast instead. Here's an example using the values you posted:
clrs = [0; 16777215; 16711680; 65280; 255; 65535; 16711935; 16776960]
for i=1:numel(clrs)
bgra = typecast(int32(clrs(i)), 'uint8')
end
The output:
clrs =
0
16777215
16711680
65280
255
65535
16711935
16776960
bgra =
0 0 0 0
bgra =
255 255 255 0
bgra =
0 0 255 0
bgra =
0 255 0 0
bgra =
255 0 0 0
bgra =
255 255 0 0
bgra =
255 0 255 0
bgra =
0 255 255 0
Your int2rgb method inverts R and B. Replace them and you'll get the right conversion. The Interior.Color property uses the convention where R is the least significant, while the FileExchange function you used uses the opposite convention.
To convert from int to RGB:
B = floor(colorInt / (256*256));
G = floor((colorInt - B*256*256)/256);
R = colorInt - B*256*256 - G*256;
colorRGB = [R G B];
To convert from RGB to int:
colorInt = colorRGB * [1 256 256*256]';
From the MSDN article on RGB Color Model:
The RGB color model is used for specifying colors. This model
specifies the intensity of red, green, and blue on a scale of 0 to
255, with 0 (zero) indicating the minimum intensity. The settings of
the three colors are converted to a single integer value by using this
formula:
RGB value = Red + (Green*256) + (Blue*256*256)
As it was suggested in chris neilsen answer, there is no "right" or "wrong" in terms of color encoding. Microsoft has chosen this particular way to encode colors for reasons only they know, and I should stick to it.
So the RGB values that I get are totally correct.
In the following table, I have included the RGB values provided in the MSDN article next to the ones that I get in MATLAB, and they are a perfect match.
Color Int RGB values from MSDN
-------- -------- --------
Black 0 0
White 16777215 16777215
Red 255 255
Green 65280 65280
Blue 16711680 16711680
Cyan 16776960 16776960
Magenta 16711935 16711935
Yellow 65535 65535
I was trying to incrementally change the background color of a cell to black, and I found that the Range.Interior.Color method returns a Long which is seemingly arbitrary. Looking at the documentation on MSDN, there is nearly nothing about what this number represents. Is there a way to return the RGB value from this long. I effectively need the opposite of the RGB(red, green, blue) function.
That "arbitrary" number is a mathematical combination of the RGB values (B256^2 + G256 + R) and a conversion of the hex color value to a decimal number (base 16 to base 10), depending on which way you want to look at it. Just different bases. Below is the method I use in the XLAM addin file I wrote for Excel. This method has come in handy many times. I have included the documentation in my addin file.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Function Color
' Purpose Determine the Background Color Of a Cell
' #Param rng Range to Determine Background Color of
' #Param formatType Default Value = 0
' 0 Integer
' 1 Hex
' 2 RGB
' 3 Excel Color Index
' Usage Color(A1) --> 9507341
' Color(A1, 0) --> 9507341
' Color(A1, 1) --> 91120D
' Color(A1, 2) --> 13, 18, 145
' Color(A1, 3) --> 6
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function Color(rng As Range, Optional formatType As Integer = 0) As Variant
Dim colorVal As Variant
colorVal = rng.Cells(1, 1).Interior.Color
Select Case formatType
Case 1
Color = WorksheetFunction.Dec2Hex(colorVal, 6)
Case 2
Color = (colorVal Mod 256) & ", " & ((colorVal \ 256) Mod 256) & ", " & (colorVal \ 65536)
Case 3
Color = rng.Cells(1, 1).Interior.ColorIndex
Case Else
Color = colorVal
End Select
End Function
good to see that Mr Wyatt uses the fast method of color to RGB
R = C Mod 256
G = C \ 256 Mod 256
B = C \ 65536 Mod 256
which is many times faster than those using hex str with left mid right
that some recommend
Short Answer:
There is no built in functionality for this. You must write your own function.
Long Answer:
The long that is returned from the Interior.Color property is a decimal conversion of the typical hexidecimal numbers that we are used to seeing for colors in html e.g. "66FF66". Additionally the constant xlNone (-4142) can be passed to set cell to have no color in the background, however such cells are marked white RGB(255, 255, 255) from the Get property. Knowing this, we can write a function that returns one or all of the appropriate RGB values.
Luckily, a kind Mr. Allan Wyatt has done just that here!
Determining the RGB Value of a Color
The other answer did not work for me. I found that:
R = C And 255
G = C \ 256 And 255
B = C \ 256 ^ 2 And 255
and it worked properly.
This is another way to skin the cat
'
' Type definition in declarations
'
Type RGBcolor
r As Long
g As Long
b As Long
End Type
'
' Inverse RGB function
'
Function GetRGB(ByVal x As Long) As RGBcolor
With GetRGB
.r = x Mod 256
x = x \ 256
.g = x Mod 256
x = x \ 256
.b = x Mod 256
End With
End Function
'
' Sub to test the GetRGB function
'
Sub test(x As Long)
Dim c As RGBcolor
c = GetRGB(x) ' returns RGB values: c.r, c.g, c.b
Debug.Print "Original", "Red", "Green", "Blue", "Recombined value"
Debug.Print x, c.r, c.g, c.b, RGB(c.r, c.g, c.b)
End Sub
'
'
***** IMMEDIATE WINDOW *****
test 1000
Original Red Green Blue Recombined value
1000 232 3 0 1000
Should note, for the hex values, if you're exporting out to HTML you're going to get quirks too.
Ideally you'd create the hex string from the individual colours, rather than returning a hex from the ColorVal number.
The reason being you can get some invalid hex numbers if the cell is a 'pure' colour like green/blue
RED - RGB(255,0,0) returns 'FF' - it should return 'FF0000'
BLUE - RGB(0,0,255) returns 'FF00000' - it should return '0000FF'
enter image description here
If you used these to create HTML/CSS colour output, you'd get RED for any blue cells.
I modified the script to assemble each two character hex 'chunk' based on the RGB values, with a UDF that just pads with a leading 0 where output of one character is returned ( hopefully if you're reading this, you can make something similar )
Color = ZeroPad(Hex((colorVal Mod 256)), 2) & ZeroPad(Hex(((colorVal \ 256) Mod 256)), 2) & ZeroPad(Hex((colorVal \ 65536)), 2)
--Edit : forgot to include the code for the UDF...
Function ZeroPad(text As String, Cnt As Integer) As String
'Text is the string to pad
'Cnt is the length to pad to, for example ZeroPad(12,3) would return a string '012' , Zeropad(12,8) would return '00000012' etc..
Dim StrLen As Integer, StrtString As String, Padded As String, LP As Integer
StrLen = Len(Trim(text))
If StrLen < Cnt Then
For LP = 1 To Cnt - StrLen
Padded = Padded & "0"
Next LP
End If
ZeroPad = Padded & Trim(text)
ENDOF:
End Function
BTW - If you want the hex codes as displayed in the form editor ( which inexplicably has it's own standard , apart from the normal HTML Hex Colours )
Case 4 ' ::: VBA FORM HEX :::
Color = "&H00" & ZeroPad(Hex((colorVal \ 65536)), 2) & ZeroPad(Hex(((colorVal \ 256) Mod 256)), 2) & ZeroPad(Hex((colorVal Mod 256)), 2) & "&"
Mark Balhoff´s VBA script works fine. All credits go to him.
In case you´d like to get the color codes/indexes of conditionally formatted cells as well, the code may be amended like this:
'----------------------------------------------------------------
' Function Color
' Purpose Determine the Background Color Of a Cell
' #Param rng Range to Determine Background Color of
' #Param formatType Default Value = 0
' 0 Integer color of cell, not considering conditional formatting color
' 1 Hex color of cell, not considering conditional formatting color
' 2 RGB color of cell, not considering conditional formatting color
' 3 Excel Color Index color of cell, not considering conditional formatting color
' 4 Integer "real" visible color of cell (as the case may be the conditional formatting color)
' 5 Hex "real" visible color of cell (as the case may be the conditional formatting color)
' 6 RGB "real" visible color of cell (as the case may be the conditional formatting color)
' 7 Excel Color Index "real" visible color of cell (as the case may be the conditional formatting color)
' Usage Color(A1) --> 9507341
' Color(A1, 0) --> 9507341
' Color(A1, 1) --> 91120D
' Color(A1, 2) --> 13, 18, 145
' Color(A1, 3) --> 6
'-----------------------------------------------------------------
Function Color(rng As Range, Optional formatType As Integer = 0) As Variant
Dim colorVal As Variant
Select Case formatType
Case 0 To 3
colorVal = Cells(rng.Row, rng.Column).Interior.Color
Case 4 To 7
colorVal = Cells(rng.Row, rng.Column).DisplayFormat.Interior.Color
End Select
Select Case formatType
Case 0
Color = colorVal
Case 1
Color = Hex(colorVal)
Case 2
Color = (colorVal Mod 256) & ", " & ((colorVal \ 256) Mod 256) & ", " & (colorVal \ 65536)
Case 3
Color = Cells(rng.Row, rng.Column).Interior.ColorIndex
Case 4
Color = colorVal
Case 5
Color = Hex(colorVal)
Case 6
Color = (colorVal Mod 256) & ", " & ((colorVal \ 256) Mod 256) & ", " & (colorVal \ 65536)
Case 7
Color = Cells(rng.Row, rng.Column).DisplayFormat.Interior.ColorIndex
End Select
End Function
Short Answer
Drop these 3 self-explanatory one-liner's into a module, then use them in VBA or worksheet formulas:
Function rr(rgbCode): rr = rgbCode Mod 256: End Function
Function g(rgbCode): g = (rgbCode \ 256) Mod 256: End Function
Function b(rgbCode): b = rgbCode \ 65536: End Function
(I couldn't use a single R for red's function name since it's reserved for use in the Goto F5 & Name CTRL+F3 dialogs.)
Let's assume i have the following range from (a1:c3)
A B C
1 -1 1 1
2 -1 0 0
3 0 0 1
Now i have selected the following range, and formatted it using Conditional Formatting (using default red yellow green color scale).... now range colors became
A B C
1 Green Red Red
2 Green Yellow Yellow
3 Yellow Yellow Red
Now I want to ask the color of any cell in the range, for example MsgBox Range("A1").Interior.Color
but it does not say that it is Green, why? Plz can you help me?
Range("A1").Interior.Color always returns 16777215
Range("A1").Interior.ColorIndex always returns -4142
(no matter whether the color of A1 is red, blue, green, ...)
Range("A1", "C3").FormatConditions.Count
this one returns always 0, why?
.Interior.Color returns the "real" color, not the conditionally-formatted color result.
#sss: It's not available via the API.
The best you can do is to test the same conditions you used in the conditional formatting.
To avoid this resulting in duplicate code, I suggest moving your conditional criteria to a UDF. Examples:
Function IsGroup1(ByVal testvalue As Variant) As Boolean
IsGroup1 = (testvalue < 0)
End Function
Function IsGroup2(ByVal testvalue As Variant) As Boolean
IsGroup1 = (testvalue = 0)
End Function
Function IsGroup3(ByVal testvalue As Variant) As Boolean
IsGroup1 = (testvalue > 0)
End Function
Then use these formulas in your Conditional formatting:
=IsGroup1(A1)
=IsGroup2(A1)
=IsGroup3(A1)
Then your code, rather than looking at the color of the cells, looks to see if the condition is met:
If IsGroup1(Range("$A$1").Value) Then MsgBox "I'm red!"
You need to refer the <Cell>.FormatConditions(index that is active).Interior.ColorIndex to retrieve the conditional formatting color of a cell.
You may refer to the below link for an example:
http://www.xldynamic.com/source/xld.CFConditions.html#specific
As a follow up to #richardtallent (sorry, I couldn't do comments), the following link will get you a function that returns you the color index by evaluating the conditional formatting for you.
http://www.bettersolutions.com/excel/EPX299/LI041931911.htm
To get the color of a cell in a Range, you need to reference the individual cell inside the array in the form of Range("A1","C3").Cells(1,1) (for cell A1). The Excel help is pretty good if you look up the name of the property you're having issues with.
Also, Excel 2007 uses Integers for its color types, so your best bet is to assign the color index to an integer, and using that throughout your program. For your example, try:
Green = Range("A1","C3").Cells(1,1).Interior.Color
Yellow = Range("A1","C3").Cells(1,3).Interior.Color
Red = Range("A1","C3").Cells(2,1).Interior.Color
And then to switch the colors to all red:
Range("A1","C3").Interior.Color = Red
Again, check the Excel help for how to use Cells([RowIndex],[ColumnIndex]).
If the above doesn't work for you, check to see what .Interior.PatternColorIndex is equal to. I typically leave it set at xlAutomatic (solid color), and it could be set to something else if the color isn't changing.
According to XlColorIndex Enumeration ColorIndex=-4142 means No color
As to why this happens I'm clueless. The returned value seems to be the decimal representation of the RGB value. The improved version of this script to decrypt the value into hex RGB notation
Function RGB(CellRef As Variant)
RGB = ToHex(Range(CellRef).Interior.Color)
End Function
Function ToHex(ByVal N As Long) As String
strH = ""
For i = 1 To 6
d = N Mod 16
strH = Chr(48 + (d Mod 9) + 16 * (d \ 9)) & strH
N = N \ 16
Next i
strH2 = ""
strH2 = Right$(strH, 2) & Mid$(strH, 3, 2) & Left$(strH, 2)
ToHex = strH2
End Function
It doesn't appear that the "Conditional Format"-color is available programmatically. What I'd suggest that, instead, you write a small function that calculates cell color, and then just set a macro to run it on the active cell whenever you've edited the value. For example (sorry for the psuedo-code - I'm not a VBA expert anymore):
Function GetColorForThisCell(Optional WhatCell as String) as Int
If WhatCell="" Then WhatCell = ActiveCell
If Range(WhatCell).value = -1 then GetColorForThisCell = vbGreen
If Range(WhatCell).value = 0 then GetColorForThisCell = vbYellow
If Range(WhatCell).value = 1 then GetColorForThisCell = vbRed
End Function
Sub JustEditedCell
ActiveCell.color = GetColorForThisCell()
End Sub
Sub GetColorOfACell(WhatCell as string)
Msgbox(GetColorForThisCell(WhatCell) )
End Sub
Though you wouldn't be able to use the built-in Excel Conditional Formatting, this would accomplish the same thing, and you'd be able to read the color from code. does this make sense?
since i may have more than three different colors in a time... i didn't find any good way of handling this with conditional formatting's default colors... i did it this way. then whenever i ask the color of the cell, i retrieve the correct color!
for (int t = 0; t < d_distinct.Length; t++ )
{
Excel.FormatCondition cond =
(Excel.FormatCondition)range.FormatConditions.Add(
Excel.XlFormatConditionType.xlCellValue,
Excel.XlFormatConditionOperator.xlEqual,
"="+d_distinct[t],
mis, mis, mis, mis, mis);
cond.Interior.PatternColorIndex =
Excel.Constants.xlAutomatic;
cond.Interior.TintAndShade = 0;
cond.Interior.Color = ColorTranslator.ToWin32(c[t]);
cond.StopIfTrue = false;
}
d_distinct holds all the distinct values in a range... c is a Color[] which holds distinct colors for every distinct value! this code can easily be translated to vb!