Fastest way to Hide empty rows from Cell Range using Excel VBA - excel

I had this code to hide an entire row if the range of cells are empty. It works fine but the problem is, it takes to long to show the result.
Here is my code:
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
Dim xRg As Range
For Each xRg In Range("D22:D728")
If xRg.Value = "" Then
xRg.EntireRow.Hidden = True
Else
xRg.EntireRow.Hidden = False
End If
Next xRg
End Sub

Try this..
Range("D22:D728").SpecialCells(xlCellTypeBlanks).EntireRow.Hidden = True

Found the answer to my question. Thank you for sharing your codes. just added some work around from this site.
Private Sub Worksheet_PivotTableUpdate(ByVal Target As PivotTable)
Range("D22:D728").EntireRow.Hidden = False
Dim cell As Range, unionRng As Range
For Each cell In ActiveSheet.Range("D22:D728")
If cell.Value = 0 Then
If Not unionRng Is Nothing Then
Set unionRng = Union(unionRng, cell)
Else
Set unionRng = cell
End If
End If
Next
If Not unionRng Is Nothing Then unionRng.EntireRow.Hidden = True
End Sub

Try screen updating:
Sub Stop_ScreenUpdate ()
Application.ScreenUpdating = false
" your code "
Application.ScreenUpdating = True
End Sub

Related

Excel VBA Worksheet_Change for a Range of values

I have a problem with VBA, I need to use the worksheet change event to pickup cell values from AI28 to AI30 and move them over to V28 to V30. This is what I have do so far
Private Sub Worksheet_Change(ByVal Target As Range)
If IsNumeric(Target) And Not (Target = "") Then
If Target.Address = Range("AI28:AI30").Address Then
Range("V28:V30").Value = Range("AH28:AH30").Value
Else
If Target.Cells.Value <> Empty Then Exit Sub
Exit Sub
End If
End If
End Sub
It works fine for just one range eg AI28 and V28 so what am I missing? A loop or something?
Use a loop and Intersect:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Intersect(Target, Me.Range("AI28:AI30"))
If rng Is Nothing Then Exit Sub
On Error GoTo SafeExit
Application.EnableEvents = False
Dim cell As Range
For Each cell In rng
If IsNumeric(cell.Value) And Not IsEmpty(cell.Value) Then
Me.Range("V" & cell.Row).Value = cell.Value
End If
Next
SafeExit:
Application.EnableEvents = True
End Sub

Multiple Worksheet_Change events in VBA code

I want to merge two Worksheet_Change events.
The aim of the code is to convert any uppercase text in the cell ranges given to lowercase.
I tried copying both into the same Worksheet_Change, but Excel crashed.
Range 1:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ccr As Range
Set ccr = Range("C6")
For Each Cell In ccr
Cell.Value = LCase(Cell)
Next Cell
End Sub
Range 2:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim acr As Range
Set acr = Range("C9:G9")
For Each Cell In acr
Cell.Value = LCase(Cell)
Next Cell
End Sub
The main issue is that changing a cell value Cell.Value will trigger another Worksheet_Change immediately. You need to Application.EnableEvents = False to prevent this.
Also I recommend to work with Intersect so the code only runs on the cells that are actually changed.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim AffectedRange As Range
Set AffectedRange = Intersect(Target, Target.Parent.Range("C6, C9:G9"))
If Not AffectedRange Is Nothing Then
Application.EnableEvents = False 'pervent triggering another change event
Dim Cel As Range
For Each Cel In AffectedRange.Cells
Cel.Value = LCase$(Cel.Value)
Next Cel
Application.EnableEvents = True 'don't forget to re-enable events in the end
End If
End Sub
In addition to #Frank Ball's comment including error handling:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim AffectedRange As Range
Set AffectedRange = Intersect(Target, Target.Parent.Range("C6, C9:G9"))
Application.EnableEvents = False 'pervent triggering another change event
On Error GoTo ERR_HANDLING
If Not AffectedRange Is Nothing Then
Dim Cel As Range
For Each Cel In AffectedRange.Cells
Cel.Value = LCase$(Cel.Value)
Next Cel
End If
On Error GoTo 0
'no Exit Sub here!
ERR_HANDLING:
Application.EnableEvents = True
If Err.Number <> 0 Then
Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
End If
End Sub
Like this you can do both the things in same event
You have to add Application.EnableEvents = False at the starting to avoid race condition.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Dim ccr As Range, acr as Range
Set ccr = Range("C6")
For Each Cell In ccr
Cell.Value = LCase(Cell)
Next Cell
Set acr = Range("C9:G9")
For Each Cell In acr
Cell.Value = LCase(Cell)
Next Cell
Application.EnableEvents = True
End Sub
The two Worksheet_Change events are quite the same, they are a loop around a range, returning LCase(). Thus, it is a good idea to make a separate Sub for it like this:
Sub FixRangeLCase(rangeToFix As Range)
Dim myCell As Range
For Each myCell In rangeToFix
myCell.Value2 = LCase(myCell.Value2)
Next myCell
End Sub
Then, refer the Worksheet_Change event to it. As far as the Worksheet_Change event is quite "expensive", running always, it is a good idea to run it only when a specific Target cell is changed and otherwise exit the procedure - If Intersect(Target, Range("C6"), Range("C9:G9")) Is Nothing Then Exit Sub
The Application.EnableEvents = False is needed to disable the events. At the end it is set back to True.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("C6"), Range("C9:G9")) Is Nothing Then Exit Sub
Application.EnableEvents = False
FixRangeLCase Range("C6")
FixRangeLCase Range("C9:G9")
Application.EnableEvents = True
End Sub
Also you can use:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range, cell As Range
Application.EnableEvents = False
If Not Intersect(Target, Range("C6")) Is Nothing Or Not Intersect(Target, Range("C9:G9")) Is Nothing Then
Set rng = Range("C9:G9", "C6")
For Each cell In rng
cell.Value = LCase(cell.Value)
Next
End If
Application.EnableEvents = True
End Sub

Save previous cell VALUES and not only the last one (modify my code)

I found this interesting code that is almost perfect for my needs.
When a cell changes value, this code save the old value in another cell.
The problem is that when I change it again, it overwrite the previous "old value". So, at the end, I only have my "N value" and my "N-1 value".
What should I do to keep all the previous values?
Let's say that I'm modifying the cell A1, the old value goes to B1.
I thought about a CONCATENATE function, save the B1 somewhere else, but I feel I'm going in a wrong way.
Thank you so much for your patience and time.
Dim xRg As Range
Dim xChangeRg As Range
Dim xDependRg As Range
Dim xDic As New Dictionary
Private Sub Worksheet_Change(ByVal Target As Range)
Dim I As Long
Dim xCell As Range
Dim xDCell As Range
Dim xHeader As String
Dim xCommText As String
On Error Resume Next
Application.ScreenUpdating = False
Application.EnableEvents = False
xHeader = "Previous value :"
x = xDic.Keys
For I = 0 To UBound(xDic.Keys)
Set xCell = Range(xDic.Keys(I))
Set xDCell = Cells(xCell.Row, 7)
xDCell.Value = ""
xDCell.Value = xDic.Items(I)
Next
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim I, J As Long
Dim xRgArea As Range
On Error GoTo Label1
If Target.Count > 1 Then Exit Sub
Application.EnableEvents = False
Set xDependRg = Target.Dependents
If xDependRg Is Nothing Then GoTo Label1
If Not xDependRg Is Nothing Then
Set xDependRg = Intersect(xDependRg, Range("C:C"))
End If
Label1:
Set xRg = Intersect(Target, Range("C:C"))
If (Not xRg Is Nothing) And (Not xDependRg Is Nothing) Then
Set xChangeRg = Union(xRg, xDependRg)
ElseIf (xRg Is Nothing) And (Not xDependRg Is Nothing) Then
Set xChangeRg = xDependRg
ElseIf (Not xRg Is Nothing) And (xDependRg Is Nothing) Then
Set xChangeRg = xRg
Else
Application.EnableEvents = True
Exit Sub
End If
xDic.RemoveAll
For I = 1 To xChangeRg.Areas.Count
Set xRgArea = xChangeRg.Areas(I)
For J = 1 To xRgArea.Count
xDic.Add xRgArea(J).Address, xRgArea(J).Formula
Next
Next
Set xChangeRg = Nothing
Set xRg = Nothing
Set xDependRg = Nothing
Application.EnableEvents = True
End Sub

Excel VBA to automatically capitalise causing error when pasting

The code below is causing an error when I paste information onto the sheet.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A1 As Range
Set A1 = Range("A:I")
If Not Intersect(Target, A1) Is Nothing Then
Application.EnableEvents = False
Target.Value = UCase(Target.Value)
Application.EnableEvents = True
End If
End Sub
The code is specific to the sheet (right click on tab an view code).
Could you please advise on how to fix this?
Thanks in advance.
Loop over the intersection cells if they exists:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A1 As Range, intr As Range, r As Range
Set A1 = Range("A:I")
Set intr = Intersect(A1, Target)
If Not intr Is Nothing Then
Application.EnableEvents = False
For Each r In intr
r.Value = UCase(r.Value)
Next r
Application.EnableEvents = True
End If
End Sub
The error is because of Target.Value = UCase(Target.Value) is not suitable for multiple cells. Thus a loop is needed:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo WorksheetChange_Error
Application.EnableEvents = False
Dim A1 As Range
Set A1 = Range("A:I")
If Not Intersect(Target, A1) Is Nothing Then
Dim myCell As Range
For Each myCell In Target.Cells
myCell = UCase(myCell)
Next
End If
Application.EnableEvents = True
Exit Sub
WorksheetChange_Error:
Application.EnableEvents = True
MsgBox Err.Description
End Sub
The error handler is used to reset the EnableEvents = True, if some kind of unexpected error comes.

Dynamic Search with highlight - Excel VBA

I would like to achieve the following:
In my excel sheet I have a set of data to which I've applied dynamic filtering by creating a "Search box".
The filtering itself works okay, no problems there, however, I would like to further improve it, by highlighting the text (that is entered into the search box) in the filtered rows in red.
I am attaching a screenshot of what I would like to see in the final version.
Any idea how this can be entered into my current code?
As always, any help is greatly appreciated!
Thank you!
Below is the code I use for the dynamic filtering:
Private Sub TextBox1_Change()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
If Len(TextBox1.Value) = 0 Then
Sheet1.AutoFilterMode = False
Else
If Sheet1.AutoFilterMode = True Then
Sheet1.AutoFilterMode = False
End If
Sheet1.Range("B4:C" & Rows.Count).AutoFilter field:=1, Criteria1:="*" & TextBox1.Value & "*"
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Consider something like this - Write in a worksheet the following:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
If Target <> Range("a1") Then Exit Sub
SelectAndChange (Target)
End Sub
Private Sub SelectAndChange(strValue As String)
Dim rngCell As Range
Dim rngRange As Range
Dim strLookFor As String
Dim arrChar As Variant
Dim lngCounter As Long
If strValue = vbNullString Then Exit Sub
Application.EnableEvents = False
Set rngRange = Range("E1:E10")
rngRange.Font.Color = vbBlack
strLookFor = Range("A1").Value
For Each rngCell In rngRange
For lngCounter = 1 To Len(rngCell) - Len(strLookFor) + 1
If Mid(rngCell, lngCounter, Len(strLookFor)) = strLookFor Then
rngCell.Characters(lngCounter, Len(strLookFor)).Font.Color = vbRed
End If
Next lngCounter
Next rngCell
Application.EnableEvents = True
End Sub
The values in E1:E10 would be dependent from the value in A1 like this:

Resources