excel vba change textbox based on values - vba

I am trying to change the font color based on the values in the cells(16,3).
For some reason it is not working. The present value at 16,3 is 94% and it is showing up in green color instead of amber. Your help would be appreciated.
Private Sub TextBox1_Change()
TextBox1.Value = Cells(16, 3).Text
Cells(16, 3).Font.Bold = True
If TextBox1.Value > 95 Then TextBox1.ForeColor = RGB(0, 128, 0) 'Green
If TextBox1.Value > 80 And TextBox1.Value < 95 Then TextBox1.ForeColor = RGB(255, 153, 0) 'Amber
If TextBox1.Value < 80 Then TextBox1.ForeColor = RGB(255, 0, 0) 'Red
End Sub

You'll get that result if the value in the cell is in text format rather than as an actual value. Is it possible that that's the case?
The other thing to bear in mind, though this wouldn't be the cause of your existing problem or the text would always be red, is that 94% is actually 0.94, not 94.
Edit: (I'm doing an edit to my original answer in response to the comment because I need to include code which does not go into comments well)
You have a few other problems.
The first is that if this is being driven by the value in cell(16,3) I'm not sure that you should be driving it from the Textbox1_Change event. By doing that you are waiting for someone to enter a value into that text box and immediately overwriting it with whatever is in that cell. Better to populate the entry during the form load.
Much depends on what you're trying to do with this, and I have no information on that.
Second, if you step through the code you'll find that TextBox1.Value is returning a string; it has double quotes around it. But you are comparing it to a numeric set of values.
The third is that your code does not deal with the situation where there is an exact match of (say) 80%.
The fourth is that if you suck the value straight from the cell, and it really is a percentage value, it'll come up as 0.94, not formatted as a percentage.
This deals with the lot.
Dim rng As Excel.Range
Set rng = ActiveSheet.Cells(16,3)
TextBox1.Value = Format(rng.Value, "00%")
rng.Font.Bold = True
'You should really implement error checking here.
'There's no point reading the value from the textbox if it's coming from a cell.
'Just use the cell value.
If rng.Value >= 0.95 Then
TextBox1.ForeColor = RGB(0, 128, 0) 'Green
ElseIf rng.Value >= 0.8 And rng.Value < 0.95 Then
TextBox1.ForeColor = RGB(255, 153, 0) 'Amber
ElseIf rng.Value < 0.8 Then
TextBox1.ForeColor = RGB(255, 0, 0) 'Red
End If
Set rng = Nothing

If you use
TextBox1.Value = Cells(16, 3).Value
instead of
TextBox1.Value = Cells(16, 3).Text
You will see the real values used in your if statements. And result will be like below:
If Text Type of related cell is : "General"
And if you use related cell type as "Percentage". You will get following results
So, depending on your preferences you can either use the cell value as general or you can convert it in the macro from percentage to general and display it as it is.
If you want to keep using Percentage in your related sheet which means actually as value you will have 0.XX in that cell however it will display as XX%, then you can simply multiply your value with 100 as follows:
TextBox1.Value = Cells(16, 3).Value * 100

Related

VBA UserForms - comparind data in userform

I have two files. One file is with specification, second with the reuslts. I've created UserForm where I can compare if result is within the specified range & result is assessed as OK or NOK.
Spec
Results
Results & specification is saved from excel to tables & from table are populated into UserForm. During this, I met situation where randowm result (not the same) is within the range of specification but final Judgment is NOK. All data (spec& results) are in "General" format.
UserForm
When I will write the same result manualy, then Judgment is OK. I have 14 windows which are working with below the same code (numbers are just different)
Private Sub txtVal14_AfterUpdate()
Val14 = CofC_FORM.txtVal14.Value
If CofC_FORM.Test14 <> "" Then
If CofC_FORM.Val14 >= CofC_FORM.Min14 Then
If CofC_FORM.Val14 <= CofC_FORM.Max14 Then
CofC_FORM.Jud14.Caption = "OK"
CofC_FORM.Jud14.BackColor = RGB(102, 255, 51)
Else: CofC_FORM.Jud14.Caption = "NOK"
CofC_FORM.Jud14.BackColor = RGB(255, 51, 0)
End If
Else: CofC_FORM.Jud14.Caption = "NOK"
CofC_FORM.Jud14.BackColor = RGB(255, 51, 0)
End If
Else: CofC_FORM.Jud14.Caption = ""
End If
End Sub
I thought there are string valuse to compare & I implemented in the step before below code to change string to the number:
For Each r In Sheets(i).Range("G23:G28").SpecialCells(xlCellTypeConstants)
r.Select
r.NumberFormat = "0.00"
String1 = r.Value
String1 = Replace(String1, ",", ".")
r.Value = CSng(String1)
Next r
Can someone help me ? Do you have any idea what could be the problem as I think, aboce code is OK.

Modifying format of individual characters per cell per range based on capitalization. Excel random errors

Trying to make an Acronym list for work. First column list the acronym. Second column spells out the acronym while keeping the main components capitalized.
Ex. | POC | Point Of Contact |
Goal is to format the capitalized characters for easier viewing by making them bold, increasing the size, and changing the color to red.
Ex. | POC | Point Of Contact | ------------imagine letters are red and bigger
Since I have 1,000+ acronyms to deal with I created a VBA code to check each character per cell and format the correct ones. Below you can find my code.
Excel can handle some phrases fine while choking then crashing on others. I've tried to check for patterns as to why without any luck.
Other times Excel will act in unpredictable ways such as duplicating the leading letter or highlighting the rest of the phrase red. When comparing the text value in the formula bar vs what's visible in the cell, one can see a difference
Example of error
These troubled cells have a tendency to corrupt the file if saved and re-opened.
Is there something inherently wrong with my code, or is Excel just being buggy for some reason? Would there be a different way to do this without causing excel to have bugs and corrupt the file?
UPDATE: Another Example of Error Running the suggested code
Sub Acronym_List_Formatting()
Dim cll As Range
Dim i As Long
Dim q As Integer
Dim Char As String
Dim UChar As String
Dim Phrase() As String
q = Application.InputBox("Set the base font size", Default:=12, Type:=1)
'| Set initial formatting of everything |'
With Selection.Font
.Name = "Calibri"
.Size = q
.Bold = False
.Color = vbBlack
End With
'| Main Code |'
For Each cll In Selection
ReDim Phrase(Len(cll.Value))
For i = 1 To Len(cll.Value)
Char = Mid$(cll.Value, i, 1)
UChar = UCase$(Char)
Phrase(i) = Char
If Asc(UChar) >= 65 And Asc(UChar) <= 90 Then '|Asc returns the ASCII value ; Continues only if character is a letter|'
If Char = UChar Then
With cll.Characters(i, 1).Font
.Bold = True
.Size = .Size + 1.5
.Color = vbRed
End With
End If
End If
Next i
'Debug.Print "Phrase: " & Join(Phrase)
MsgBox ("Phrase: " & Join(Phrase, ""))
Next cll
End Sub
UPDATE(2): An excerpt of my data for testing
Amcom[aviation and missile command] Engineering Directorate
c2BmC[command and control, battle management and communication] element lead
Bmds[ballistic missile defense system] Opir[overhead persistent infrared] Architecture
Jtids[joint tactical information distribution system] Interface Control
Nato[north atlantic treaty organization] General Communications System
Osf[objective simulation framework] Public Interface
Patriot[phased array tracking radar intercept on target] Advanced Capability 3 SIMulation
Patriot[phased array tracking radar intercept on target] Anti‐Cruise Missile
Patriot[phased array tracking radar intercept on target] Conduct Of Fire Trainer
RW[] Integrated ToolSet
Sm‐3[standard missile‐3] Cooperative Development
SPAWAR[Space & Naval Warfare Systems Command] Systems Center PACIFIC
THaad[terminal high altitude area defense] element lead
If you only need to identify and format upper case letters you can use this:
Option Explicit
Public Sub AcronymListFormatting()
Dim fntSz As Variant, cll As Range, i As Long, char As String
fntSz = Application.InputBox("Set the base font size", Default:=12, Type:=1)
If fntSz <> False And fntSz > 7 Then 'validate user input and Cancel
Application.ScreenUpdating = False
With Selection.Font
.Name = "Calibri"
.Size = fntSz
.Bold = False
.Color = vbBlack
End With
For Each cll In Selection.Cells
For i = 1 To Len(cll.Value2)
char = Mid$(cll.Value2, i, 1)
If Asc(char) >= 65 And Asc(char) <= 90 Then 'A-Z = 65-90, a-z = 97-122
With cll.Characters(i, 1).Font
.Bold = True
.Size = .Size + 1.5
.Color = vbRed
End With
End If
Next
Next
Application.ScreenUpdating = True
End If
End Sub
To convert to proper case:
cll.Value2 = WorksheetFunction.Proper(cll.Value2)
or
cll.Value2 = StrConv(cll.Value2, vbProperCase)
Edit 1
Testing with new data:
Edit 2
The issues (random errors) were caused by corrupt text imported from external file, as seen in P. McInturff's comment bellow

Word VBA to add line the length of selection

I would like to write a Word VBA macro that inserts a vertical line the length of the selected text.
apos = Int(Selection.Information(6))
Set aLine = ActiveDocument.Shapes.AddLine(26, apos, 26, apos + 40)
aLine.Select
With Selection
.ShapeRange.Line.Weight = 3#
.ShapeRange.Line.Visible = msoTrue
.ShapeRange.Line.Style = msoLineSingle
.ShapeRange.Line.ForeColor.RGB = RGB(255, 0, 0)
End With
But that code adds the vertical line length of "40"
How do I adjust the length "40" to be the length of the selected text?
Thank you
Use exactly the same method by which you have determined the beginning of the line. The end is at the Information(wdHorizontalPositionRelativeToPage) of the last character in the Selection + 1. Here is the complete code.
Private Sub LineUnderSelection()
' 08 May 2017
Dim Rng As Range
Dim FontHeight As Single, ParaSpace As Single
Dim LineStart As Single, LineEnd As Single
With Selection
With .Range
Do While Asc(.Text) < 48
' remove excluded characters at start
.MoveEnd wdCharacter, 1
Loop
Do While Asc(Right(.Text, 1)) < 48
' remove excluded characters at end
.MoveEnd wdCharacter, -1
Loop
LineStart = .Information(wdHorizontalPositionRelativeToPage)
Set Rng = Selection.Range
Rng.SetRange .End, .End
FontHeight = Int(Rng.Font.Size)
ParaSpace = 2 - Rng.Paragraphs(1).SpaceBefore
If ParaSpace < -3 Then ParaSpace = -3
LineEnd = Rng.Information(wdHorizontalPositionRelativeToPage)
SetLine ActiveDocument, "Underscore", LineStart, LineEnd - LineStart, _
.Information(wdVerticalPositionRelativeToPage) _
+ FontHeight + ParaSpace, 1.5, vbRed
End With
End With
End Sub
As you see, I found out that the extra character isn't needed. Word extends the line to the end of the character automatically. In the process of finding this out I also discovered that Word doesn't like to underline returns. Therefore the code excludes all characters with an ASCII code of less than 48 (represents the character 1). I then applied the same rule to leading characters, likewise removing them from the selection. Please run your own tests if this is enough or too much. There are lots of characters with a code > 128 which might be offensive.
The code takes the size of the last character and adds its height to the vertical position. This is to place the line under the selected text, not above it. I added 2 points to keep a little space between the text and the line.
Word takes note of space before. Your selection might contain several paragraphs. My code only looks at the paragraph of which the last character is a member. Word seems to place the line about 3 points lower if there is SpaceBefore in the paragraph's format, almost regardless of how big that space is. But if the space is smaller than 3pt the line will be lowered correspondingly less. This examination led to this code.
ParaSpace = 2 - Rng.Paragraphs(1).SpaceBefore
If ParaSpace < -3 Then ParaSpace = -3
You may like to amend this code to place the line more precisely. You will see that the vertical position consists of the position of the selection + FondtSize + ParaSpacing.
All of the above code creates the parameters which are fed to another sub which creates the actual line. Observe that the parameters include the line width and setting the Activedocument as target and giving a name to the line. It is possible to give the same name repeatedly. Word will use its own names in additon, and they are unique. Here is the code that inserts the line. (You may prefer to make it Private)
Function SetLine(Story As Object, _
Lname As String, _
Lleft As Single, _
Llength As Single, _
Ltop As Single, _
Lwidth As Single, _
Lcol As Long) As Shape
' 20 Aug 2016
Dim Fun As Shape
Set Fun = Story.Shapes.AddLine(Lleft, Ltop, Lleft + Llength, Ltop)
With Fun
.Title = Lname
.Name = Lname
.LockAspectRatio = msoTrue
With .Line
.Weight = Lwidth
.ForeColor = Lcol
End With
.RelativeHorizontalPosition = wdRelativeHorizontalPositionPage
.RelativeVerticalPosition = wdRelativeVerticalPositionPage
.Visible = msoTrue
.WrapFormat.AllowOverlap = msoTrue
.LayoutInCell = msoFalse
.ZOrder msoSendBehindText
.LockAnchor = msoTrue
End With
Set SetLine = Fun
End Function
This code includes a lot of parameters which are not variable by means of the arguments it receives, such as LockAnchor, ZOrder etc. You may wish to change these to better meet your requirements.

Change Border Color of a Range Without Changing the Linestyle/Weight

I have a nicely formatted range of cells with different border line weights (some of them are medium thickness and some of them are thin, in no particular pattern). I want to run a macro that changes the color of the borders to grey, but every time I do it, it changes all of the border weights to xlThin automatically. I want to keep the original line thickness so I don't have to go through and change the respective ones back to xlMedium, which would be tedious.
Can someone help me out? Is this possible?
The code I currently have is simple, and it changes the color correctly. It just also changes the line weight automatically, even though I don't specify the weight or linestyle at all:
Range("NamedRange").Borders.Color = RGB(150, 150, 150)
This, on my Excel 2016, will only change the color of the cell border, without changing the size:
Sub changeColorOnly()
Dim rng As Range, cel As Range
Set rng = Range("C6:C9")
For Each cel In rng
cel.Borders.Color = RGB(150, 150, 150)
Next cel
End Sub
Does it still change the size for you?
Edit: Hm, I suspect there's something else going on in your code, as I can recolor a named range without it affecting the borders. However, just because I was already working on another alternative, you could also use these subs (and tweak as necessary)
Dim brdrTop, brdrLeft, brdrRight, brdrBtm, brdrInside
Sub changeColor()
saveBorderSize Range("myNamedRange")
Range("MyNamedRange").Borders.Color = RGB(150, 150, 150)
resetBorderSize Range("myNamedRange")
End Sub
Private Sub saveBorderSize(cel As Range)
brdrTop = cel.Borders(xlEdgeTop).Weight
brdrLeft = cel.Borders(xlEdgeLeft).Weight
brdrRight = cel.Borders(xlEdgeRight).Weight
brdrBtm = cel.Borders(xlEdgeBottom).Weight
brdrInside = cel.Borders(xlInsideHorizontal).Weight
End Sub
Private Sub resetBorderSize(cel As Range)
cel.Borders(xlEdgeTop).Weight = brdrTop
cel.Borders(xlEdgeLeft).Weight = brdrLeft
cel.Borders(xlEdgeRight).Weight = brdrRight
cel.Borders(xlEdgeBottom).Weight = brdrBtm
cel.Borders(xlInsideHorizontal).Weight = brdrInside
End Sub
Try .Borders.Color = RGB(216,216,216)
I ran the below script to try to identify the closest color to normal gridlines. My eyes are not great so check it out yourself to find the best color. BTW I agree it makes no sense that MS overrides the border color defying reason. Angry employees and too much bureaucracy - that's my theory.
Sub borcol()
Dim i As Integer
For i = 1 To 250
ActiveCell.Borders.Color = RGB(i, i, i)
ActiveCell.Offset(1, 0).Select
Next i
End Sub
To change the cell border color in a loop, using the enum value for each border makes it easy to loop through them.
This code will change the border color of the selected cell.
If there's no line the MsgBox will indicate its value.
Sub CellBorderColour()
Dim MyBorder(5 To 12) As String
Dim i As Integer
MyBorder(5) = "xlDiagonalDown"
MyBorder(6) = "xlDiagonalUp"
MyBorder(7) = "xlEdgeLeft"
MyBorder(8) = "xlEdgeTop"
MyBorder(9) = "xlEdgeBottom"
MyBorder(10) = "xlEdgeRight"
MyBorder(11) = "xlInsideVertical"
MyBorder(12) = "xlInsideHorizontal"
For i = 5 To 12
With Selection.Borders(i)
If .LineStyle > 0 Then
.Color = RGB(100, 100, 100)
Else
MsgBox ("Borders(" & MyBorder(i) & ").LineStyle is: " & .LineStyle)
End If
End With
Next i
End Sub

Excel - lots of conditional formatting converted to VBA

For an Excel spreadsheet order form, I need a way to apply conditional formatting to all rows with one macro, from row 78 down until there is no more data.
Each column has its own conditional formatting formulas. Some have multiple formulas. I tried using the Record Macro function, but since there is so much going on, the resulting VBA code is messy, and I'm not sure how to combine it all.
I don't need someone to write all the code for me, but I'm hoping I can get a little guidance to figure out how to do all of it.
There are about 15 columns that need conditional formatting applied to them. Here are a few columns to show what I'm working with:
A78:
Formula: =AND($A$78="",COUNTA(78:78)>=1) | white text, red fill | Stop
If True
C78:
Format only cells that contain > Specific Text > beginning with > M |
no format | Stop If True
Format only cells that contain > Specific Text > beginning with > F |
no format | Stop If True
Format only cells that contain > No Errors | red background, white
text
D78:
Cell value is greater than 300
You can do this fairly easily with a DO-WHILE Loop. I'll give a start for "D78" and you should be able to finish the rest.
sub formatCells()
Dim count as Integer
Range("D78").Activate
count = 0
Do While ActiveCell.Offset(count, 0).Value <> ""
If ActiveCell.Offset(count, 0).Value > 300 Then
'Do Stuff
End If
count = count + 1
Loop
End Sub
You need to create a FormatCondition object for each rule you want to set. Here are the basics for setting up a formula-based conditional format.
'Set a variable for the formatcondition to make it easier to work with.
Dim fc As FormatCondition
'Create the formatcondition.
strFormula = "=$A1=$B1"
Set fc = Range("A:A").FormatConditions.Add(Type:=xlExpression, Formula1:=strFormula) '(There is a "Formula2" property that only applies if you are using one of the built-in conditional formatting rule types. It does not apply if you are using an xlExpression rule type).
'Move it to the top of the list (optional).
fc.SetFirstPriority
'Set "Stop if True" (optional).
fc.StopIfTrue = True
'Set interior Color (optional).
fc.Interior.Color = RGB(255,0,0) 'red
'Set borders (optional).
arBorders = Array(xlLeft, xlRight, xlTop, xlBottom)
For Each borderConst In arBorders
fc.Borders(borderConst).LineStyle = xlContinuous
Next
'Set font (optional).
fc.Font.Italic = True
fc.Font.Bold = True
fc.Font.Underline = True
I would recommend setting up a procedure as below to simplify this process. I created this one for my own use. It can only set borders and fill color, but could be modified to set font attributes, etc.
Sub AddFormatCondition(rgAppliesTo, strFormula, Optional bSetFirstPriority, Optional FillColor, Optional bBorders, Optional bStopIfTrue)
Dim fc As FormatCondition
Set fc = rgAppliesTo.FormatConditions.Add(Type:=xlExpression, Formula1:=strFormula)
If Not IsMissing(bSetFirstPriority) Then
If bSetFirstPriority Then fc.SetFirstPriority
End If
If Not IsMissing(FillColor) Then
With fc.Interior
.Color = FillColor
End With
End If
If Not IsMissing(bBorders) Then
If bBorders <> 0 Then
arBorders = Array(xlLeft, xlRight, xlTop, xlBottom)
For Each borderConst In arBorders
fc.Borders(borderConst).LineStyle = xlContinuous
Next
End If
End If
fc.StopIfTrue = bStopIfTrue
End Sub