Excel VBA- Toggle row highlighting with each click of a macro - vba

I have a macro that highlights a row if there is anything blank text in a specific column. This macro is used to highlight areas where a user needs to direct attention. I want to be able to unhighlight those rows after changes have been made, by clicking the same macro button.
How do I do this?
This is the current macro:
Sub Macro13()
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = 2
LastRow = .Cells(.Rows.Count, "M").End(xlUp).Row
For Lrow = LastRow To Firstrow Step -1
With .Cells(Lrow, "M")
If .Value = "" Then
.EntireRow.Interior.ColorIndex = 3
End If
End With
Next Lrow
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub
My idea was to, at the beginning of the macro, check to see if any row was highlighted red. If so, run a new loop that iterates through all columns, removing the cell highlighting, and then after that loop is done, break out of the macro. This is ugly and riddled with errors, though.
Sub Macro13() 'Checks for Incorrect Countries
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = 2
LastRow = .Cells(.Rows.Count, "M").End(xlUp).Row
FirstrowA = 2
LastRowA = .Cells(.Rows.Count, "M").End(xlUp).Row
For Lrow = LastRow To Firstrow Step -1
With .Cells(Lrow, "M")
If .EntireRow.Interior.ColorIndex = 3 Then
For LrowA = LastRowA To FirstrowA Step -1
.EntireRow.Interior.ColorIndex = xlColorIndexNone
Next LrowA
End
Exit Sub
End If
If .Value = "" Then
.EntireRow.Interior.ColorIndex = 3
End If
End With
Next Lrow
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub

This should do the trick for you. I've added a loop that looks for any formatting before it starts highlighting blanks. If if finds something red, it clears the whole sheet of red formatting and raises a flag (Tracker = True). When the flag is raised, the macro will not
format blank cells' rows as red. I tested it and it worked for me.
Sub Macro13()
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = 2
LastRow = .Cells(.Rows.Count, "M").End(xlUp).Row
Dim Tracker As Boolean
Tracker = False
For Lrow = LastRow To Firstrow Step -1
If .Cells(Lrow, "M").EntireRow.Interior.ColorIndex = 3 Then
.Cells.Interior.ColorIndex = 0
Tracker = True
Exit For
End If
Next Lrow
If Tracker = False Then
For Lrow = LastRow To Firstrow Step -1
With .Cells(Lrow, "M")
If .Value = "" Then
.EntireRow.Interior.ColorIndex = 3
End If
End With
Next Lrow
End If
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub

I've had a similar issue before and conditional formating didn't work well for me. I used something similar to this:
Sub CheckAndHighlight(area As Range, Optional ByVal searchValue As String = "")
Application.ScreenUpdating = False
Dim r As Range
For Each r In area
r.EntireRow.Interior.ColorIndex = 0
If r.Value = searchValue Then
r.EntireRow.Interior.ColorIndex = 3
End If
Next
Application.ScreenUpdating = True
End Sub

Related

Summary sheet created from multiple worksheets using a dynamic range

I have a 176 worksheets in a workbook, that all have the same format/structure, but are a difference size in row length.
I want to copy the data that is held in range A10:V(X) where X is a calculable number. This data will be pasted underneath each other, in columns B:W of the main sheet "RDBMergeSheet" and the name of the sheet that each row came from will be pasted into Column A of RDBMergeSheet so it can be seen which rows came from which sheets
X = (The lowest used row number in column J) - 3
If it makes it easier, another way to calculate X is find the row number in column A that contains the word "total" and subtract 1 from it.
The following link contains an example of such a sheet, with sanitised data.
https://imgur.com/a/emlZj
The code I've got so far, with help, is:
Sub ImportData()
Dim x As Long
Dim LR As Long
Dim wks As Worksheet
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
Set wks = Sheets("RDBMergeSheet"): If Not wks Is Nothing Then wks.Delete
Set wks = Worksheets.Add(after:=Worksheets(Sheets.Count))
wks.Name = "RDBMergeSheet"
For x = 1 To Worksheets.Count - 1
LR = Application.Max(1, Sheets(x).Cells(Rows.Count, 10).End(xlUp).Row - 3)
With wks.Cells(Rows.Count, 1)
.Offset(1, 1).Resize(LR, 22).Value = .Cells(1, 10).Resize(LR, 22).Value
.Offset(1).Resize(LR - 9).Value = Sheets(x).Name
End With
Next x
wks.Select
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
Set wks = Nothing
End Sub
This errors out with a 1004: Application defined or object defined error on line
.Offset(1, 1).Resize(LR, 22).Value = .Cells(1, 10).Resize(LR, 22).Value
If anyone has any ideas on either how to resolve this I would be extremely grateful.
Please give this a try and tweak it as per your requirement to make sure the correct data is copied starting from the correct row on destination sheet.
Sub ImportData()
Dim LR As Long, dLR As Long, i As Long
Dim wks As Worksheet
With Application
.Calculation = xlCalculationManual
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
On Error Resume Next
Set wks = Sheets("RDBMergeSheet")
wks.Cells.Clear
On Error GoTo 0
If wks Is Nothing Then
Set wks = Worksheets.Add(after:=Worksheets(Sheets.Count))
wks.Name = "RDBMergeSheet"
End If
For i = 1 To Worksheets.Count - 1
If Worksheets(i).Name <> wks.Name Then
LR = Application.Max(1, Sheets(i).Cells(Rows.Count, 10).End(xlUp).Row - 3)
If LR > 9 Then
If wks.Range("B1").Value = "" Then
dLR = 1
Else
dLR = wks.UsedRange.Rows.Count + 1
End If
wks.Range("B" & dLR & ":X" & LR - 9).Value = Worksheets(i).Range("B10:X" & LR).Value
wks.Range("A" & dLR).Value = Worksheets(i).Name
End If
End If
Next i
On Error Resume Next
wks.Select
dLR = wks.UsedRange.Rows.Count
wks.Range("A1:A" & dLR).SpecialCells(xlCellTypeBlanks).Formula = "=R[-1]C"
wks.Range("A1:A" & dLR).Value = wks.Range("A1:A" & dLR).Value
With Application
.Calculation = xlCalculationAutomatic
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
End With
Set wks = Nothing
End Sub

Removing Rows - Code Too Slow

I have the following which I am using to remove all rows of data where the name in column DX is not a specified name. The code will sort through all rows and delete each row that doesn't contain that specific name. The problem is, it is way too slow.
Any thoughts?
Sub DeleteNonName()
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = 2
Lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "DX")
If Not IsError(.Value) Then
If InStr(.Value, "Name") = 0 Then .EntireRow.Delete
End If
End With
Next Lrow
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub
Sub DeleteName()
With ActiveSheet
.AutoFilterMode = False
With Range("DX1", Range("DX" & Rows.Count).End(xlUp))
.AutoFilter 1, "Name"
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
.AutoFilterMode = False
End With
Selection.AutoFilter
End Sub

Macro to Format Sheet(s) that Contain Specific Text

I currently have a macro that formats an excel file. I was curious if there was a way to have this format all sheets that contain a specific text in the title. I'll have a workbook with numerous tab for various companies with a little different formatting requirements for each company and some months a few companies will be different. If the sheets don't exist, then ignore and move on..... Any help would be greatly appreciated.
Worksheets("DEN BS Assets").Select
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
Cells.Select
Cells.EntireColumn.AutoFit
Columns("A:A").Select
Selection.ColumnWidth = 12
Columns("A:A").Select
Selection.Replace What:="X", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = 9
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "A")
If Not IsError(.Value) Then
Select Case .Value
Case Is = "Denver", "Inactive", "System:": .EntireRow.Delete
End Select
End If
End With
Next Lrow
End With
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = 7
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "A")
If Not IsError(.Value) Then
Select Case .Value
Case Is = "Net Change", "Account:": .EntireRow.Insert
End Select
End If
End With
Next Lrow
End With
With ActiveSheet.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = 7
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "A")
If Not IsError(.Value) Then
Select Case .Value
Case Is = "Net Change", "Totals:": .EntireRow.Delete
End Select
End If
End With
Next Lrow
End With
Range("A50000").Select
Selection.End(xlUp).Offset(-1, 0).Select
Selection.Insert Shift:=xlToRight
Selection.EntireRow.Insert
Range("A50000").Select
Selection.End(xlUp).Offset(-1, 0).Select
Selection.Insert Shift:=xlToRight
Range("A50000").Select
Selection.End(xlUp).Offset(0, 0).Select
Selection.Insert Shift:=xlToRight
Columns("F").ColumnWidth = 20
With ActiveSheet.PageSetup
.PrintTitleRows = "$1:$8"
.Orientation = xlLandscape
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = False
End With
Rows("9:9").Select
ActiveWindow.FreezePanes = True`
I have made some changes to your code, remove some unnecessary Select statements (although not all as wasn't sure what the end section does). Also don't think you need two loops to insert and then delete rows.
Sub x()
Dim ws As Worksheet
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
For Each ws In Worksheets
If ws.Name Like "Denver*" Then
ws.Cells.EntireColumn.AutoFit
ws.Columns("A:A").ColumnWidth = 12
ws.Columns("A:A").Replace What:="X", Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
With ws
.DisplayPageBreaks = False
Firstrow = 9
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "A")
If Not IsError(.Value) Then
Select Case .Value
Case Is = "Denver", "Inactive", "System:": .EntireRow.Delete
End Select
End If
End With
Next Lrow
End With
With ws
Firstrow = 7
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "A")
If Not IsError(.Value) Then
Select Case .Value
Case Is = "Net Change", "Account:": .EntireRow.Insert
End Select
End If
End With
Next Lrow
End With
With ws
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "A")
If Not IsError(.Value) Then
Select Case .Value
Case Is = "Net Change", "Totals:": .EntireRow.Delete
End Select
End If
End With
Next Lrow
End With
ws.Range("A50000").End(xlUp).Offset(-1, 0).Resize(, 2).Insert shift:=xlToRight
ws.Range("A50000").End(xlUp).Offset(-1, 0).EntireRow.Insert
ws.Range("A50000").End(xlUp).Insert shift:=xlToRight
ws.Columns("F").ColumnWidth = 20
With ws.PageSetup
.PrintTitleRows = "$1:$8"
.Orientation = xlLandscape
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = False
End With
ws.Rows("9:9").Select
ActiveWindow.FreezePanes = True
End If
Next ws
End Sub

VBA - Delete either row above or row below

I have an Excel sheet with the following structure:
What I need to do is delete an entire record if either it's Type A or Type B are = 0. As an example, for record 1, I need to delete A & B because B = 0.
I have the following code:
Sub Loop_Example()
Dim Firstrow As Long
Dim Lastrow As Long
Dim Lrow As Long
Dim CalcMode As Long
Dim ViewMode As Long
With Application
CalcMode = .Calculation
.Calculation = xlCalculationManual
.ScreenUpdating = False
End With
With ActiveSheet
.Select
ViewMode = ActiveWindow.View
ActiveWindow.View = xlNormalView
.DisplayPageBreaks = False
Firstrow = .UsedRange.Cells(1).Row
Lastrow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
For Lrow = Lastrow To Firstrow Step -1
With .Cells(Lrow, "B")
If Not IsError(.Value) Then
If .Value = "0" Then .EntireRow.Delete
End If
End With
Next Lrow
End With
ActiveWindow.View = ViewMode
With Application
.ScreenUpdating = True
.Calculation = CalcMode
End With
End Sub
Therefore, what I would like to do is add the logic to delete the entire row if the value is 0 and either the row above or below depending on its 'type'.
Thanks.
this should work.
Sub pDeleteRow()
Dim wksData As Worksheet
Dim rngCell As Range
Dim lngCounter As Long
Dim lngTotalCount As Long
Set wksData = Worksheets("Sheet1")
lngTotalCount = wksData.Range("A1").CurrentRegion.Rows.Count
lngCounter = 1
With wksData
While lngCounter <= lngTotalCount
If (UCase(Trim(.Cells(lngCounter, 2))) = "A" Or UCase(Trim(.Cells(lngCounter, 2))) = "B") And UCase(Trim(.Cells(lngCounter, 3))) = "0" Then
.Cells(lngCounter, 1).EntireRow.Delete
lngCounter = lngCounter - 1
lngTotalCount = lngTotalCount - 1
End If
lngCounter = lngCounter + 1
Wend
End With
End Sub
You can Try This:
Sub ConditionalRowDelete()
Set colA = Range("C1", Cells(Rows.Count, "C").End(xlUp))
Set colB = Range("D1", Cells(Rows.Count, "D").End(xlUp))
MsgBox colA.Rows.Count
For i = 1 To colA.Rows.Count
If colB(i) = 0 Then
If colA(i) = "A" Then
'colB(i).Select
With colB(i) 'Selection
Application.Union(.EntireRow, .Offset(1, 0).EntireRow).Delete 'Select
End With
'Selection.EntireRow.Select
'MsgBox "found A"
End If
If colA(i) = "B" Then
'colB(i).Select
With colB(i) 'Selection
Application.Union(.EntireRow, .Offset(-1, 0).EntireRow).Delete 'Select
End With
'MsgBox "found B"
End If
End If
Next
End Sub

Auto sort and format and Excel

I have a table of clients in Excel, and I want to be able to add new client into the last row of the table and excel will sort the table automatically so that the client's name will be sorted in alphabetical order.
Also, that the format will be similar to the previous line. for example, the second column is DOB, so I want the format to be the same as the previous row MM/DD/YYYY
Thanks
Put the attached code in your worksheet module and it will sort your column A automatically.
Private Sub Worksheet_Change(ByVal Target As Range)
'turn off updates to speed up code execution
With Application
.ScreenUpdating = False
.EnableEvents = False
.Calculation = xlCalculationManual
.DisplayAlerts = False
End With
If Not Intersect(Target, Columns(1)) Is Nothing Then
With ActiveSheet.Sort
.SetRange Range("A1:X" & Cells(Rows.Count, 1).End(xlUp).Row)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Columns("B").NumberFormat = "MM/DD/YYYY"
End If
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = xlCalculationAutomatic
.DisplayAlerts = True
End With
End Sub
Here's a piece of VBA that would auto-add your table as soon as the first cell on the last row gets typed in. You would have to provide IsChangeInLastLineOfStrRange function and call AddEmptyRowWhenFull from the change-event. It might need tweaking since I removed some code from it. The original has a recursion timer to prevent ... well ... recursion.
Public Sub AddEmptyRowWhenFull(SheetName As String, Area As String, Target As Range)
Dim rngDatabase As Range
With Sheets(SheetName)
If IsChangeInLastLineOfStrRange(SheetName, Area, Target) _
And Target.Value <> "" Then
Set rngDatabase = .Range(Area)
AddEmptyRow rngDatabase, rngDatabase.Rows.Count
End If
End With
End Sub
Public Sub AddEmptyRow(Database As Range, RowPosition As Long, Optional ClearLine As Boolean = True)
Dim bScreenupdate, iCalculation As Integer
Dim colnum As Long, markrow As Long
Dim bUpdate As Boolean
bScreenupdate = Application.ScreenUpdating
iCalculation = Application.Calculation
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
With Database
If RowPosition < .Rows.Count Then
.Rows(RowPosition - 0).Copy 'Insert in and after data
.Rows(RowPosition + 1).Insert shift:=xlDown
Else
.Rows(RowPosition - 0).Copy 'Add line at end by inserting before last line
.Rows(RowPosition - 0).Insert shift:=xlDown ' to prevent cell formatting below it to be copied too
RowPosition = RowPosition + 1 'Clear last of the copies
End If
If ClearLine = False Then 'Move cursor down
ActiveSheet.Cells(ActiveCell.row + 1, ActiveCell.column).Activate
Else
For colnum = 1 To .Columns.Count 'Preserve formula's
If Not .Rows(RowPosition).Cells(1, colnum).HasFormula Then 'changed
.Rows(RowPosition).Cells(1, colnum).ClearContents
End If
Next colnum
End If
'Fix rowheight if we shift into other heights
.Rows(RowPosition + 1).RowHeight = .Rows(RowPosition + 0).RowHeight
End With
If bScreenupdate = True Then Application.ScreenUpdating = True
If Not iCalculation = xlCalculationManual Then Application.Calculation = iCalculation
End Sub
Arjen.