Flashing cells in VBA - vba

I have got a bit of code where when a cell is of a certain value it changes its interior to red and its font to white. what i want to do is to make the colour of the text alternate between white and red every second as long as the cells interior is red (once it turns red it will remain red).
i want the user to have the impression that the cell is actually flashing.
i wrote this code:
For r = 6 To 1000
With .Cells(r, 6)
While .Interior.Color = RGB(237, 67, 55)
.Font.Color = RGB(237, 67, 55)
Application.Wait (Now + TimeValue("0:00:01"))
.Font.Color = vbWhite
Wend
End With
Next r
excel just makes the first cell that has red interior "flash" ones and then crashes. the red cells are not in consecutive order.

Have a go with:
Sub Flash_Ahhh()
Dim strRange As String
Dim rCell As Range
Dim iFlasher As Integer
lngCounter = Cells.Find("*", [A1], , , xlByRows, xlPrevious).Row 'Find last row of data
lngCol = ActiveCell.Column ' Find the active column
vArr = Split(Cells(1, lngCol).Address(True, False), "$")
Col_Letter = vArr(0) 'The Active Column Letter
strRange = Col_Letter & "6:" & Col_Letter & lngCounter 'The range of all cells in the active column
For Each rCell In Range(strRange).Cells
Select Case rCell.Interior.Color
Case Is = vbRed
For iFlasher = 1 To 10
If rCell.Font.Color = vbRed Then
rCell.Font.Color = vbWhite
Else
rCell.Font.Color = vbRed
End If
Call WaitFor(0.1)
Next iFlasher
rCell.Font.Color = vbWhite
Case Else
End Select
Next rCell
End Sub
Use the following to cause the time delay:
Sub WaitFor(NumOfSeconds As Single)
Dim SngSec As Single
SngSec = Timer + NumOfSeconds
Do While Timer < SngSec
DoEvents
Loop
End Sub

Related

hide column based on font color in a table vba

I have some data in sheet1 as a table (named Table1), and I am changing the font color for some headers based on name and I want to only hide the header if its font color is black so keep orange and white un-hide. When I open the original worksheet, column headers has font color of white.
Right now when I run my codes, there are no error, but I only see columns with headers of orange font color which is not correct. For some reason when I convert my data into range, it works but I don't want to use unlist and re-create a table for the data.
Sub Data_Formatting()
Dim i, j, k As Long
Range(Range("A1"), Range("A1").End(xlToRight)).Interior.Color = RGB(79, 129, 189)
Last = Cells(1, Columns.Count).End(xlToLeft).Column
For i = Last To 1 Step -1
If (Cells(1, i).Value) = "System" Then
Cells(1, i).Font.Color = RGB(0, 0, 0)
End If
Next i
For j = Last To 1 Step -1
If (Cells(1, j).Value) = "AOB" Then
Cells(1, j).Font.Color = RGB(255, 153, 0)
End If
Next j
Range("A:D").Columns.AutoFit
Dim l As Long
Dim lColumn As Long
Dim ws As Worksheet: Set ws = ActiveSheet
'Last column
lColumn = ws.Cells(1, Columns.Count).End(xlToLeft).Column
For l = 1 To lColumn
If Cells(1, l).Font.Color = RGB(0, 0, 0) Then
Cells(1, l).EntireColumn.Hidden = True
Else
Cells(1, l).EntireColumn.Hidden = False
End If
Next
End Sub
You only need to loop once here and do all of your logic in that one loop. The way you are doing it now is looping three times over the same set of columns just to perform slightly different actions.
Sub Data_Formatting()
Dim i as Long
'set the background to blue
Range(Range("A1"), Range("A1").End(xlToRight)).Interior.Color = RGB(79, 129, 189)
'Find last cell
Last = Cells(1, Columns.Count).End(xlToLeft).Column
'autofit before hiding
Range("A:D").Columns.AutoFit
'loop once
For i = Last To 1 Step -1
If (Cells(1, i).Value) = "System" Then
Cells(1, i).Font.Color = RGB(0, 0, 0) 'black
Columns(i).Hidden = True
ElseIf Cells(1, j).Value = "AOB" Then
Cells(1, j).Font.Color = RGB(255, 153, 0) 'orange
Columns(i).Hidden = False
End If
Next i
End Sub
With this change we don't have to bother detecting the cell color since you are setting that based on the value in the same loop. Test the value, set the color, and hide it all in one shot.

Excel VBA - merge cells if values in columns equals

I'm trying to figure out how to implement a macro to get results as follows:
I have no idea how to do it. This is what I've done so far.
I want to have additional column "Action" and if value in column "State" for e.g R1 is empty or "no_fix" then QM (green) else QA (red).
I have data with ~5000 rows
Hi, thanks it works as I expected. However, after testing of my data it turned out that I need to check additional conditions.
1.Additionally for QM and QA:
check in column G if value = "ST"
check in column H if value = 0
2.QA
check in column C if value = "No TC for LM" check in column D if
value = "no state" check in column E if value = "No IPIS" if any of
values = true then QA
Sub MergeSameCell()
'area
Dim Rng As Range, xCell As Range, Test As Range
Dim Rng1 As Range
Dim xRows As Integer
xTitleId = "Merge duplicated cells"
Set WorkRng = Application.Selection
Set WorkRng = Application.InputBox("Range", xTitleId, WorkRng.Address,
Type:=8)
Application.ScreenUpdating = False
Application.DisplayAlerts = False
xRows = WorkRng.Rows.Count
For Each Rng In WorkRng.Columns
For i = 1 To xRows - 1
For j = i + 1 To xRows
'If Rng.Cells(i, 1).Value > 0 And Rng.Cells(j, 1).Value > 0 Then
If Rng.Cells(i, 1).Value <> Rng.Cells(j, 1).Value Then
Exit For
End If
Next
'WorkRng.Parent.Range(Rng.Cells(i, 1), Rng.Cells(j - 1, 1)).Merge
'Text = WorkRng.Parent.Range(Rng.Cells(i, 1), Rng.Cells(j - 1, 1))
i = j - 1
For Each Rng1 In Range(Rng.Cells(i, 1), Rng.Cells(j - 1, 1))
For Z = 1 To 13
'MsgBox i
'MsgBox j
If Rng1.Offset(Z, 1).Value = "no_to_fix" Or Rng1.Offset(Z,
1).Value
= "" Then
'WorkRng.Parent.Range(Rng.Cells(i, 1), Rng.Cells(j - 1,
1)).Merge
Rng1.Cells.Offset(Z, 1).Interior.ColorIndex = 37
'MsgBox "supcio"
End If
Next
Next
Next
Next
WorkRng.VerticalAlignment = xlCenter
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
The following code will do the merging you want and, if I understand what you mean by the second part of the question, will set the first column to be either "QM" (if the fourth column is never anything other than blank or "no_fix") or "QA".
Code assumes you will use the InputBox to select a range containing four columns, the first being the column that will contain "QM" or "QA", the second being the column that is your "Req" column, and the fourth being your "State" column. (The code never looks at what is in the third column.)
Sub MergeSameCell()
Dim WorkRng As Range
xTitleId = "Merge duplicated cells"
Set WorkRng = Selection
Set WorkRng = Application.InputBox("Range", xTitleId, WorkRng.Address, Type:=8)
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim startRow As Long
Dim endRow As Long
Dim r As Long
Dim isQM As Boolean
'Use "startRow" to keep track of the start of each block
startRow = 1
With WorkRng
'Loop through each row in the selected range
For endRow = 1 To .Rows.Count
If .Cells(endRow + 1, 2).Value <> .Cells(startRow, 2).Value Then
'Only do something if the next row has a different value in the second column
'merge rows in the first and second columns
.Worksheet.Range(.Cells(startRow, 1), .Cells(endRow, 1)).MergeCells = True
.Worksheet.Range(.Cells(startRow, 2), .Cells(endRow, 2)).MergeCells = True
'Check for "no_fix" or blank
isQM = True ' Assume it is a "QM" until we determine it isn't
For r = startRow To endRow
If .Cells(r, 4).Value <> "" And .Cells(r, 4).Value <> "no_fix" Then
'If the 4th column is not blank and is not "no_fix", it isn't a "QM"
isQM = False
Exit For
End If
Next
'Update column 1 to show QM or QA
With .Cells(startRow, 1)
If isQM Then
.Value = "QM"
.Interior.Color = vbGreen
Else
.Value = "QA"
.Interior.Color = vbRed
End If
End With
'Point to start of next block
startRow = endRow + 1
End If
Next
End With
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub

Autoformat row based on values in each cell using Excel VBA?

I have Table1
Column A has a Date e.g. 30/5/2017
Column B has Status e.g "Success"
Column C has Value e.g 500
Requirement: Apply custom Conditional formatting in VBA when a cell is changed
Let's say the change happened in Columns A, B or C in row 5
Regardless whether the change happened in Columns A, B, or C, the same logic should be executed.
If column A value is less than Now(), then row 5 should be red background and white text. No further checks should run.
Else If column B is "Success", then row 5 should be green background and white text. No further checks should run.
Else If column C has value less than 500, then row 5 should be blue background and white text. No further checks should run.
The VBA code below is to check for change on a cell - it autoformats cell in column b with a hyperlink.
What I need now is to autoformat the whole row based on the criteria above.
Private Sub Worksheet_Change(ByVal Target As Range)
If ((Not Intersect(Target, Range("B:B")) Is Nothing) Or (Not Intersect(Target, Range("F:F")) Is Nothing) Or (Not Intersect(Target, Range("G:G")) Is Nothing) Or (Not Intersect(Target, Range("I:I")) Is Nothing)) Then
End If
End Sub
Try this code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Rng As Range, R As Range
Dim fCol As Long, bCol As Long
Set Rng = Application.Intersect(Target, Columns("A:C"))
If Not Rng Is Nothing Then
Set Rng = Application.Intersect(Rng.EntireRow, Columns("A:C"))
fCol = vbWhite
For Each R In Rng.Rows
If R.Cells(1, 1).Value <> vbNullString And R.Cells(1, 1).Value < Now Then
bCol = vbRed
ElseIf R.Cells(1, 2).Value <> vbNullString And R.Cells(1, 2).Value = "Success" Then
bCol = vbGreen
ElseIf R.Cells(1, 3).Value <> vbNullString And R.Cells(1, 3).Value < 500 Then
bCol = vbBlue
Else
bCol = xlNone
fCol = vbBlack
End If
R.EntireRow.Interior.Color = bCol
R.EntireRow.Font.Color = fCol
Next
End If
End Sub
Edit:
I have Table1
If Table1 is a ListObject (Excel tables) then we can modify the above code to make it watch first three columns of this table regardless of where the first column is starting (in column "A" or "B" or etc..), and format only the table row not the EntireRow :
Private Sub Worksheet_Change(ByVal Target As Range)
Dim LObj As ListObject
Dim RngToWatch As Range
Dim Rng As Range, R As Range
Dim fCol As Long, bCol As Long
Set LObj = ListObjects("Table1") ' the name of the table
Set RngToWatch = Range(LObj.ListColumns(1).DataBodyRange, LObj.ListColumns(3).DataBodyRange)
Set Rng = Application.Intersect(Target, RngToWatch)
If Not Rng Is Nothing Then
Set Rng = Application.Intersect(Target.EntireRow, RngToWatch)
fCol = vbWhite
For Each R In Rng.Rows
If R.Cells(1, 1).Value <> vbNullString And R.Cells(1, 1).Value < Now Then
bCol = vbRed
ElseIf R.Cells(1, 2).Value <> vbNullString And R.Cells(1, 2).Value = "Success" Then
bCol = vbGreen
ElseIf R.Cells(1, 3).Value <> vbNullString And R.Cells(1, 3).Value < 500 Then
bCol = vbBlue
Else
bCol = xlNone
fCol = vbBlack
End If
With Application.Intersect(LObj.DataBodyRange, R.EntireRow)
.Interior.Color = bCol
.Font.Color = fCol
End With
Next
End If
End Sub
I am assuming your table (having three columns) are present in Sheet1.
So, add following code in Sheet1 (not in separate module)
Private Sub Worksheet_Change(ByVal Target As Range)
Dim irow As Variant
' First identify the row changed
irow = Target.Row
' Invoke row formatter routine
Call DefineFormat(irow)
End Sub
Then add following piece of code in a module (you may add under Sheet1 as well but it will limit the uses of this module)
Sub DefineFormat(irow) ' Receive the row number for processing
Dim vVal As Variant
Dim Rng As Range
Dim lFont, lFill As Long
' Define the basis for validation
Dim Current, Success, limit As Variant ' Can be defined as constant as well
Current = Date ' Set today's date
Success = "Success" ' Set success status check
limit = 500 ' Set limit for value check
' Set range for the entire row - Columns A(index 1) to Column C (index 3)
Set Rng = Range(Application.ActiveSheet.Cells(irow, 1).Address, Application.ActiveSheet.Cells(irow, 3).Address)
lFont = vbWhite
' Assuming columns A, B and C needs to be formatted
If Application.ActiveSheet.Cells(irow, 1) < Current Then
lFill = vbRed ' Check for col A
Else:
If Application.ActiveSheet.Cells(irow, 2) = Success Then
lFill = vbGreen ' Check for col B
Else
If Application.ActiveSheet.Cells(irow, 3) < limit Then
lFill = vbBlue ' Check for col C
Else ' Default formatting
lFill = xlNone
lFont = vbBlack
End If
End If
End If
Rng.Interior.Color = lFill
Rng.Font.Color = lFont
End Sub
This will format the row as the data is modified (just like conditional formatting)
Also, if you need to format the entire table in one go, then you may call DefineFormat routine in a loop for each row of the table as illustrated by Fadi in his reply.

How can I use .EntireRow but skip column A?

Looking for either a workaround or some idea on how I can use the code excerpt below, but skip column A.
Basically, I'm using
.EntireRow(a.Row).Interior.Color = color
to highlight rows based on a userform selection, but I need to skip column A as it has headers that have their own highlighting.
Any ideas?
If ToggleButton3.Value = True Then
On Error Resume Next
For iRow = 1 To 15
If Sheets("Prop" & iRow).Visible <> xlSheetVisible Then
Else
With Sheets("Prop" & iRow).Range("$E$1:$E$157")
Set a = .Find(SlctdPAX, LookIn:=xlValues, LookAt:=xlWhole)
.EntireRow(a.Row).Interior.Color = RGB(255, 255, 102) 'yellow
End With
End If
Next iRow
ElseIf ToggleButton1.Value = True Then
On Error Resume Next
For iRow = 1 To 15
If Sheets("Prop" & iRow).Visible <> xlSheetVisible Then
Else
With Sheets("Prop" & iRow).Range("$E$1:$E$157")
Set a = .Find(SlctdPAX, LookIn:=xlValues, LookAt:=xlWhole)
.EntireRow(a.Row).Interior.Color = RGB(255, 0, 0) 'red
End With
End If
Next iRow
ElseIf ToggleButton4.Value = True Then
On Error Resume Next
For iRow = 1 To 15
If Sheets("Prop" & iRow).Visible <> xlSheetVisible Then
Else
With Sheets("Prop" & iRow).Range("$E$1:$E$157")
Set a = .Find(SlctdPAX, LookIn:=xlValues, LookAt:=xlWhole)
.EntireRow(a.Row).Interior.Color = xlNone 'no fill
End With
End If
Next iRow
ElseIf ToggleButton2.Value = True Then
On Error Resume Next
For iRow = 1 To 15
If Sheets("Prop" & iRow).Visible <> xlSheetVisible Then
Else
With Sheets("Prop" & iRow).Range("$E$1:$E$157")
Set a = .Find(SlctdPAX, LookIn:=xlValues, LookAt:=xlWhole)
.EntireRow(a.Row).Interior.Color = RGB(128, 255, 0) 'green
End With
End If
Next iRow
Else
End If
Lets say a is a single cell.
With regards to exclude highlighting column A,
to highlight entire row of a, do:
a.EntireRow.Resize(, Columns.Count - 1).Offset(, 1).Interior.Color
to highlight multiple rows staked together below a, e.g. 5 rows, do:
a.EntireRow.Resize(5, Columns.Count - 1).Offset(, 1).Interior.Color
to highlight multiple rows which are not staked together, e.g. entire rows of [E1], [E3], [E5], do:
Intersect(Union([E1], [E3], [E5]).EntireRow, Cells.Resize(, Columns.Count - 1).Offset(, 1))
FYI, just tested that Union([E1], [E3], [E5]).EntireRow.Resize() is not allowed.
Hope this helps.
With ThisWorkbook.Sheets("Prop" & iRow)
Set a = .Range("$E$1:$E$157").Find(SlctdPAX, LookIn:=xlValues, LookAt:=xlWhole)
a.EntireRow.Resize(1, .Cells(a.row, .Columns.Count - 1).column).Offset(, 1).Interior.Color = RGB(255, 0, 0) 'red
End With
which is quite much whar KS Sheon has already posted.
but I'm afraid his code, being inside With Sheets("Prop" & iRow).Range("$E$1:$E$157") block , would color all rows from 1 to 157.
moreover Columns.Count would count the number of columns of the active sheet, which may not be the one wanted

Unable to split cell content by line breaks

My VBA script is supposed to split content in one cell by line breaks into several rows, it works for some cells, date in one cell look like this:
a01gestmstrs2a 10.67.15.17
a01gestmdb2a 10.67.15.19
a01gstdbldnim1a
a01rstdbldnim1a
a01gestmstrs2b (10.67.15.46)
a01restmdb2a (10.67.15.48)
a01gestmstrs2z 10.67.15.20
a01gestmdb2b (10.67.15.47)
a01restmstrs2a (10.67.15.49)
However, it fails to split for some such as the sample provided above, I can't figure out why.
My code:
Sub SplitMultipleHostnames()
Dim tmpArr As Variant
Dim s As String
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
For Each cell In Range("D2", Range("D3").End(xlDown))
For Each c In ActiveSheet.UsedRange
s = c.Value
If Trim(Application.Clean(s)) <> s Then
s = Trim(Application.Clean(s))
c.Value = s
End If
If cell.Value <> "" Then
If InStr(1, cell, Chr(10)) <> 0 Then
tmpArr = Split(cell, Chr(10))
cell.EntireRow.Copy
cell.Offset(1, 0).Resize(UBound(tmpArr), 1).EntireRow.Insert xlShiftDown
cell.Resize(UBound(tmpArr) + 1, 1) = Application.Transpose(tmpArr)
End If
Else
cell.EntireRow.Delete
cell.Row = cell.Row - 1
End If
Next
Next
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Application.CutCopyMode = False
End Sub
The loop that uses Trim() and Clean() will remove all ASCII 10's and 13's from the worksheet.
There will be nothing to Split().
They are not actually Char(10) they are spaces. I changed the code to " " and it worked fine
If cell.Value <> "" Then
If InStr(1, cell, " ") <> 0 Then
tmpArr = Split(cell, " ")