Why is VBA array not loading integers - vba

Here is a function I found online to help loop through values and select pivot filter items that match the values. My problem is that the array created in the Sub Filter_Bana does not get loaded with the values from the range named as "Bana" (aka varItemList). The range "Bana" consists of about twenty numbers (integers). When I run the sub (at the bottom), I keep receiving the MsgBox "None of filter list items found" from the function. I have been trying to figure this out for a while and don't think any of the named integer list "Bana" is getting loaded into "varItemList." In other words, when varItemList is passed to the function, the array is empty. Please see code:
**EDIT: I found the problem. The problems I was having related to two issues: 1) I am bad at VBA, 2) the data type of the pivot items in my pivot field did not match the data type of the array. I switched the array components to a 5-character text and adjusted the SQL query to bring in my investorNumber as a 5-character text (i.e. the array needed to be loaded with a character string and my pivot field needed data of the character type; if there was a way to do this with integers, I'd love to know. **
Private Function Filter_PivotField(pvtField As PivotField, _
varItemList As Variant)
Dim strItem1 As Long, blTmp As Boolean, i As Long
On Error Resume Next
Debug.Print varItemList
Application.ScreenUpdating = False
With pvtField
If .Orientation = xlPageField Then .EnableMultiplePageItems = True
For i = LBound(varItemList) To UBound(varItemList)
blTmp = Not (IsError(.PivotItems(varItemList(i)).Visible))
If blTmp Then
strItem1 = .PivotItems(varItemList(i))
Exit For
End If
Next i
If strItem1 = "" Then
MsgBox "None of filter list items found."
Exit Function
End If
.PivotItems(strItem1).Visible = True
For i = 1 To .PivotItems.Count
If .PivotItems(i) <> strItem1 And _
.PivotItems(i).Visible = True Then
.PivotItems(i).Visible = False
End If
Next i
For i = LBound(varItemList) To UBound(varItemList)
.PivotItems(varItemList(i)).Visible = True
Next i
End With
Application.ScreenUpdating = True
End Function
Sub Filter_Bana()
Filter_PivotField _
pvtField:=Sheets("Pres1&2_Pivot").PivotTables("PivotTable1").PivotFields("investorNumber"), _
varItemList:=Application.Transpose(Sheets("Controls").Range("Bana"))
End Sub`

This code works. The only other key is making sure my array is loaded with character type data (not integers) and that the pivot field also contains character type data (adjusted in the query/not displayed)
Private Function Filter_PivotField(pvtField As PivotField, _
varItemList As Variant)
Dim strItem1 As String, blTmp As Boolean, i As Long
Application.ScreenUpdating = False
With pvtField
If .Orientation = xlPageField Then .EnableMultiplePageItems = True
For i = LBound(varItemList) To UBound(varItemList)
blTmp = Not (IsError(.PivotItems(varItemList(i)).Visible))
If blTmp Then
strItem1 = .PivotItems(varItemList(i))
Exit For
End If
Next i
If strItem1 = "" Then
MsgBox "None of filter list items found."
Exit Function
End If
.PivotItems(strItem1).Visible = True
For i = 1 To .PivotItems.Count
If .PivotItems(i) <> strItem1 And _
.PivotItems(i).Visible = True Then
.PivotItems(i).Visible = False
End If
Next i
For i = LBound(varItemList) To UBound(varItemList)
.PivotItems(varItemList(i)).Visible = True
Next i
End With
Application.ScreenUpdating = True
End Function
Sub Filter_Bana()
Filter_PivotField _
pvtField:=ThisWorkbook.Worksheets("Pres1_2_Pivot").PivotTables("PivotTable1").PivotFields("investorNumber"), _
varItemList:=Application.Transpose(Sheets("Controls").Range("Bana"))
End Sub

Related

Macro fires 50% of the time when changing slicer item

I have a particular problem and couldn't find any solution anywhere on the internet.
So I have a pivot table which is connected to 6 slicers and also a chart which data range is dependent on pivot table values.
I've made a macro which updates chart scales everytime a value in any of the worksheet cells is changed. Here is the macro:
Public Sub worksheet_Change(ByVal Target2 As Range)
If ActiveSheet.Name = "Dashboard" Then
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.DataEntryMode = xlOff
'Chart_axis Macro
Sheets("Dashboard").ChartObjects("Chart 9").Activate
If ActiveSheet.Range("B19") = "excluding CE" Then
ActiveChart.Axes(xlValue).MinimumScale = Range("E3").Value
ActiveChart.Axes(xlValue).MaximumScale = Range("E4").Value
Else
ActiveChart.Axes(xlValue).MinimumScale = Range("A3").Value
ActiveChart.Axes(xlValue).MaximumScale = Range("A4").Value
End If
ActiveChart.Refresh
ActiveSheet.Range("B18").Select
Application.EnableEvents = True
Application.ScreenUpdating = True
End If
End Sub
In order to work as intended i also had to made a function which reads the active elements of a slicer:
Public Function GetSelectedSlicerItems(SlicerName As String) As String
Application.Volatile
Set coll = New Collection
Dim cache As Excel.SlicerCache
Dim i As Integer
Set cache = ActiveWorkbook.SlicerCaches(SlicerName)
Dim sItem As Excel.SlicerItem
Dim result As String
For Each sItem In cache.SlicerItems
If sItem.Selected And sItem.HasData Then
'Debug.Print sItem.Name
'Debug.Print sItem.HasData
'GetSelectedSlicerItems = (sItem.Name)
coll.Add sItem.Name
End If
Next sItem
For i = 1 To coll.Count
'Debug.Print coll(i)
result = result & coll(i) & ", "
Next i
result = Left(result, Len(result) - 2)
GetSelectedSlicerItems = result
End Function
My problem is that while the value of the function always updates when the slicer item is changed, the macro only does it randomly about 50% of the time.
Screenshot of my report:
The formulas containing the selected slicer items function are on the top right.
So do you have any idea how to make it work 100% of the time?
Thanks in advance,
Alan
Edit: i forgot to add that it's only the issue if only one slicer is highlited. When i select multiple slicers (with ctrl+click) it always works.

Looping through multiple named ranges and going to similar named range VBA

I would like to check multiple named ranges for a boolean True/False value. I need to check the 1-cell validation ranges (in order) and if the result is True, I need to .Select the corresponding named range (i.e., the named range without the corresponding "validation_" prefix and exit the subroutine. The following code works, but it's not DRY.
Here's a snippet to get the gist of the question, but this If-ElseIf continues for many other named ranges:
If Range("validation_name") = True Then
Range("name").Select
Exit Sub
ElseIf Range("validation_category") = True Then
Range("category").Select
Exit Sub
ElseIf Range("validation_subcategory") = True Then
Range("subcategory").Select
Exit Sub
' ... and many more...
Possibilities/Questions:
I think I could utilize either an array of named ranges and an array of resulting "go-to" named ranges?
Perhaps I could use a collection instead?
Not sure if a for loop or a while loop would be better?
some "extra dry" codes
Sub main()
Dim a As Variant
For Each a In Array("name", "category", "subcategory")
If Range("valid_" & a).Value = True Then
Range(a).Select
Exit Sub
End If
Next a
End Sub
Sub main2()
Dim r As Range, f As Range
Set r = Union(Range("validation_date"), Range("validation_name"), Range("validation_subcategory"), Range("validation_category"))
Set f = r.Find(what:="true", LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False)
If Not f Is Nothing Then Range(Replace(f.name.name, "validation_", "")).Select
End Sub
I assume that these are 1-cell ranges. If so, the following should work:
Sub SelectRange()
Dim i As long, A As Variant
A = Array("validation_name", "validation_category", "validation_subcategory")
For i = 0 To UBound(A)
If Range(A(i)).Value = True Then
Range(Split(A(i),"_")(1)).Select
Exit Sub
End If
Next i
End Sub
You can loop through all of the named ranges with something like:
Dim xlName As Name
For each xlName In ActiveWorkbook.Names
If xlName.Name Like "validation_*" And Range(xlName.Name) = True Then
Application.Goto Replace(xlName.Name, "validation_", ""), True
Exit Sub
End If
Next
or specify them like this
For each strName In Split("name category subcategory")
If Range("validation_" & strName) = True Then
Application.Goto strName, True
Exit Sub
End If
Next
Update
Sorry, I did not read the whole question. Seems like you can use some kind of key - value Collection
pairs = Array( Array( "validation_name", "name" ), _
Array( "validation_category", "category" ), _
Array( "validation_subcategory", "subcategory" ) )
For each pair In pairs
If Range( pair(0) ) = True Then
Application.Goto pair(1), True
Exit Sub
End If
Next

Check if a cell from a selected range is visible

I have a VBA function in Excel returns a concatenated string of text from cells selected by users.
This works as I require, however if there are hidden cells in the selection, the value of the hidden cell is included, which is undesirable. An example of when this issue occurs is when a table is filtered.
Is there a way to amend my function to check if the cell that is being read is visible?
Sub ConcatEmialAddresses()
Dim EmailAddresses As String
ActiveSheet.Range("C3").Value = combineSelected()
ActiveSheet.Range("C3").Select
Call MsgBox("The email address string from cell ""C3"" has been copied to your clipboard.", vbOKOnly, "Sit back, relax, it's all been taken care of...")
End Sub
Function combineSelected(Optional ByVal separator As String = "; ", _
Optional ByVal copyText As Boolean = True) As String
Dim cellValue As Range
Dim outputText As String
For Each cellValue In Selection
outputText = outputText & cellValue & separator
Next cellValue
If Right(outputText, 2) = separator Then outputText = Left(outputText, Len(outputText) - 2)
combineSelected = outputText
End Function
To determine if a Range has an hidden cell, I would check that the height/width of each row/column is different from zero:
Function HasHiddenCell(source As Range) As Boolean
Dim rg As Range
'check the columns
If VBA.IsNull(source.ColumnWidth) Then
For Each rg In source.Columns
If rg.ColumnWidth = 0 Then
HasHiddenCell = True
Exit Function
End If
Next
End If
' check the rows
If VBA.IsNull(source.RowHeight) Then
For Each rg In source.rows
If rg.RowHeight = 0 Then
HasHiddenCell = True
Exit Function
End If
Next
End If
End Function
Sub UsageExample()
If HasHiddenCell(selection) Then
Debug.Print "A cell is hidden"
Else
Debug.Print "all cells are visible"
End If
End Sub
I used this
Function areCellsHidden(Target As Range)
areCellsHidden = False
If (Target.Rows.Hidden = True) Then
areCellsHidden = True
ElseIf (Target.Columns.Hidden = True) Then
areCellsHidden = True
ElseIf (Target.Count > 1) Then
If _
Target.Count <> Target.Columns.SpecialCells(xlCellTypeVisible).Count _
Or Target.Count <> Target.Rows.SpecialCells(xlCellTypeVisible).Count _
Then
areCellsHidden = True
End If
End If
End Function

Run Time Error '1004': Paste Method Of worksheet Class Failed error

Copy pasting 1 line of text from word to excel using VBA.
When the code reaches the below line I am getting the below error.
ActiveSheet.Paste
Run Time Error '1004': Paste Method Of worksheet Class Failed error
But if I click Debug button and press F8 then it's pasting the data in excel without any error.
This error occurs each time the loop goes on and pressing debug and F8 pasting the data nicely.
I did several testing and unable to find the root cause of this issue.
Also used DoEvents before pasting the data code but nothing worked.
Any suggestions?
EDIT:-
I am posting the code since both of you are saying the same. Here is the code for your review.
Sub FindAndReplace()
Dim vFR As Variant, r As Range, i As Long, rSource As Range
Dim sCurrRep() As String, sGlobalRep As Variant, y As Long, x As Long
Dim NumCharsBefore As Long, NumCharsAfter As Long
Dim StrFind As String, StrReplace As String, CountNoOfReplaces As Variant
'------------------------------------------------
Dim oWord As Object
Const wdReplaceAll = 2
Set oWord = CreateObject("Word.Application")
'------------------------------------------------
Application.ScreenUpdating = False
vFR = ThisWorkbook.Sheets("Sheet1").Range("A1").CurrentRegion.Value
On Error Resume Next
Set rSource = Cells.SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If Not rSource Is Nothing Then
For Each r In rSource.Cells
For i = 2 To UBound(vFR)
If Trim(vFR(i, 1)) <> "" Then
With oWord
.Documents.Add
DoEvents
r.Copy
.ActiveDocument.Content.Paste
NumCharsBefore = .ActiveDocument.Characters.Count
With .ActiveDocument.Content.Find
.ClearFormatting
.Font.Bold = False
.Replacement.ClearFormatting
.Execute FindText:=vFR(i, 1), ReplaceWith:=vFR(i, 2), Format:=True, Replace:=wdReplaceAll
End With
.Selection.Paragraphs(1).Range.Select
.Selection.Copy
r.Select
ActiveSheet.Paste'Error occurs in this line pressing debug and F8 is pasting the data
StrFind = vFR(i, 1): StrReplace = vFR(i, 2)
NumCharsAfter = .ActiveDocument.Characters.Count
CountNoOfReplaces = (NumCharsBefore - NumCharsAfter) / (Len(StrFind) - Len(StrReplace))
.ActiveDocument.UndoClear
.ActiveDocument.Close SaveChanges:=False
If CountNoOfReplaces Then
x = x + 1
ReDim Preserve sCurrRep(1 To 3, 1 To x)
sCurrRep(1, x) = vFR(i, 1)
sCurrRep(2, x) = vFR(i, 2)
sCurrRep(3, x) = CountNoOfReplaces
End If
CountNoOfReplaces = 0
End With
End If
Next i
Next r
End If
oWord.Quit
'Some more gode goes here... which is not needed since error occurs in the above loop
End Sub
If you want to know why I have chosen word for replacement then please go through the below link.
http://www.excelforum.com/excel-programming-vba-macros/1128898-vba-characters-function-fails-when-the-cell-content-exceeds-261-characters.html
Also used the code from the below link to get the number of replacements count.
http://word.mvps.org/faqs/macrosvba/GetNoOfReplacements.htm
Characters(start, length).Delete() method really seems not to work with longer strings in Excel :(. So a custom Delete() method could be written which will work with decoupled formating informations and texts. So the text of the cell can be modified without loosing the formating information. HTH.
Add new class named MyCharacter. It will contain information about text and
formating of one character:
Public Text As String
Public Index As Integer
Public Name As Variant
Public FontStyle As Variant
Public Size As Variant
Public Strikethrough As Variant
Public Superscript As Variant
Public Subscript As Variant
Public OutlineFont As Variant
Public Shadow As Variant
Public Underline As Variant
Public Color As Variant
Public TintAndShade As Variant
Public ThemeFont As Variant
Add next new class named MyCharcters and wrap the code of the new
Delete method in it. With Filter method a new collection of MyCharacter is created. This collection contains only the characters which should remain. Finally in method Rewrite the text is re-written from this collection back to target range along with formating info:
Private m_targetRange As Range
Private m_start As Integer
Private m_length As Integer
Private m_endPosition As Integer
Public Sub Delete(targetRange As Range, start As Integer, length As Integer)
Set m_targetRange = targetRange
m_start = start
m_length = length
m_endPosition = m_start + m_length - 1
Dim filterdChars As Collection
Set filterdChars = Filter
Rewrite filterdChars
End Sub
Private Function Filter() As Collection
Dim i As Integer
Dim newIndex As Integer
Dim newChar As MyCharacter
Set Filter = New Collection
newIndex = 1
For i = 1 To m_targetRange.Characters.Count
If i < m_start Or i > m_endPosition Then
Set newChar = New MyCharacter
With newChar
.Text = m_targetRange.Characters(i, 1).Text
.Index = newIndex
.Name = m_targetRange.Characters(i, 1).Font.Name
.FontStyle = m_targetRange.Characters(i, 1).Font.FontStyle
.Size = m_targetRange.Characters(i, 1).Font.Size
.Strikethrough = m_targetRange.Characters(i, 1).Font.Strikethrough
.Superscript = m_targetRange.Characters(i, 1).Font.Superscript
.Subscript = m_targetRange.Characters(i, 1).Font.Subscript
.OutlineFont = m_targetRange.Characters(i, 1).Font.OutlineFont
.Shadow = m_targetRange.Characters(i, 1).Font.Shadow
.Underline = m_targetRange.Characters(i, 1).Font.Underline
.Color = m_targetRange.Characters(i, 1).Font.Color
.TintAndShade = m_targetRange.Characters(i, 1).Font.TintAndShade
.ThemeFont = m_targetRange.Characters(i, 1).Font.ThemeFont
End With
Filter.Add newChar, CStr(newIndex)
newIndex = newIndex + 1
End If
Next i
End Function
Private Sub Rewrite(chars As Collection)
m_targetRange.Value = ""
Dim i As Integer
For i = 1 To chars.Count
If IsEmpty(m_targetRange.Value) Then
m_targetRange.Value = chars(i).Text
Else
m_targetRange.Value = m_targetRange.Value & chars(i).Text
End If
Next i
For i = 1 To chars.Count
With m_targetRange.Characters(i, 1).Font
.Name = chars(i).Name
.FontStyle = chars(i).FontStyle
.Size = chars(i).Size
.Strikethrough = chars(i).Strikethrough
.Superscript = chars(i).Superscript
.Subscript = chars(i).Subscript
.OutlineFont = chars(i).OutlineFont
.Shadow = chars(i).Shadow
.Underline = chars(i).Underline
.Color = chars(i).Color
.TintAndShade = chars(i).TintAndShade
.ThemeFont = chars(i).ThemeFont
End With
Next i
End Sub
How to use it:
Sub test()
Dim target As Range
Dim myChars As MyCharacters
Application.ScreenUpdating = False
Set target = Worksheets("Demo").Range("A1")
Set myChars = New MyCharacters
myChars.Delete targetRange:=target, start:=300, length:=27
Application.ScreenUpdating = True
End Sub
Before:
After:
To make it more stable, you should:
Disable all events while operating
Never call .Activate or .Select
Paste directly in the targeted cell with WorkSheet.Paste
Cancel the Copy operation with Application.CutCopyMode = False
Reuse the same document and not create one for each iteration
Do as less operations as possible in an iteration
Use early binding [New Word.Application] instead of late binding [CreateObject("Word.Application")]
Your example refactored :
Sub FindAndReplace()
Dim dictionary(), target As Range, ws As Worksheet, cell As Range, i As Long
Dim strFind As String, strReplace As String, diffCount As Long, replaceCount As Long
Dim appWord As Word.Application, content As Word.Range, find As Word.find
dictionary = [Sheet1!A1].CurrentRegion.Value
Set target = Cells.SpecialCells(xlCellTypeConstants)
' launch and setup word
Set appWord = New Word.Application
Set content = appWord.Documents.Add().content
Set find = content.find
find.ClearFormatting
find.Font.Bold = False
find.replacement.ClearFormatting
' disable events
Application.Calculation = xlManual
Application.ScreenUpdating = False
Application.EnableEvents = False
' iterate each cell
Set ws = target.Worksheet
For Each cell In target.Cells
' copy the cell to Word and disable the cut
cell.Copy
content.Delete
content.Paste
Application.CutCopyMode = False
' iterate each text to replace
For i = 2 To UBound(dictionary)
If Trim(dictionary(i, 1)) <> Empty Then
replaceCount = 0
strFind = dictionary(i, 1)
strReplace = dictionary(i, 2)
' replace in the document
diffCount = content.Characters.count
find.Execute FindText:=strFind, ReplaceWith:=strReplace, format:=True, Replace:=2
' count number of replacements
diffCount = diffCount - content.Characters.count
If diffCount Then
replaceCount = diffCount \ (Len(strFind) - Len(strReplace))
End If
Debug.Print replaceCount
End If
Next
' copy the text back to Excel
content.Copy
ws.Paste cell
Next
' terminate Word
appWord.Quit False
' restore events
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
How about change it from: activesheet.paste
to:
activesheet.activate
activecell.pastespecial xlpasteAll
This post seems to explain the problem and provide two solutions:
http://www.excelforum.com/excel-programming-vba-macros/376722-runtime-error-1004-paste-method-of-worksheet-class-failed.html
Two items come to light in this post:
Try using Paste Special
Specify the range you wish to paste to.
Another solution would be to extract the targeted cells as XML, replace the text with a regular expression and then write the XML back to the sheet.
While it's much faster than working with Word, it might require some knowledge with regular expressions if the formats were to be handled. Moreover it only works with Excel 2007 and superior.
I've assemble an example that replaces all the occurences with the same style:
Sub FindAndReplace()
Dim area As Range, dictionary(), xml$, i&
Dim matchCount&, replaceCount&, strFind$, strReplace$
' create the regex object
Dim re As Object, match As Object
Set re = CreateObject("VBScript.RegExp")
re.Global = True
re.MultiLine = True
' copy the dictionary to an array with column1=search and column2=replacement
dictionary = [Sheet1!A1].CurrentRegion.Value
'iterate each area
For Each area In ActiveSheet.Cells.SpecialCells(xlCellTypeConstants)
' read the cells as XML
xml = area.Value(xlRangeValueXMLSpreadsheet)
' iterate each text to replace
For i = 2 To UBound(dictionary)
If Trim(dictionary(i, 1)) <> Empty Then
strFind = dictionary(i, 1)
strReplace = dictionary(i, 2)
' set the pattern
re.pattern = "(>[^<]*)" & strFind
' count the number of occurences
matchCount = re.Execute(xml).count
If matchCount Then
' replace each occurence
xml = re.Replace(xml, "$1" & strReplace)
replaceCount = replaceCount + matchCount
End If
End If
Next
' write the XML back to the sheet
area.Value(xlRangeValueXMLSpreadsheet) = xml
Next
' print the number of replacement
Debug.Print replaceCount
End Sub
DDuffy's answer is useful.
I found the code can run normally at slowly cpu PC .
add the bellow code before paste, the problem is sloved:
Application.Wait (Now + TimeValue("0:00:1"))'wait 1s or more
ActiveSheet.Paste

Delete worksheet if cells are empty

This would be a very simple question.
But I am not sure why this is not working in my excel vba code.
Sheets("I- ABC").Select
If IsEmpty(Range("A3").Value) = True And _
IsEmpty(Range("A4").Value) = True And _
IsEmpty(Range("A5").Value) = True And _
IsEmpty(Range("A6").Value) = True Then
Sheets("I- ABC").Delete
End If
What type of error do you get? I tried this code and Excel displays only warning message:
You can avoid this message by adding:
Application.DisplayAlerts = False
and
Application.DisplayAlerts = True
at the beginning and at the end of your code respectively.
--Edited code
Sub Example()
Application.DisplayAlerts = False
With Sheets("I- ABC")
If Application.WorksheetFunction.CountA(.Range("A3:A6")) = 0 Then
.Delete
End If
End With
Application.DisplayAlerts = True
End Sub
Try Similiar to This
Sub Test()
Application.DisplayAlerts = False
With Sheets("Sheet1")
Columns("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
End With
Application.DisplayAlerts = True
End Sub
PS: It works for me and deletes rows containg empty cells in `A:A``
Approach Suggested by #Tim Williams also works for me as per following code in my situation
Sub Test6()
Dim r As Range, rows As Long, i As Long
Set r = ActiveSheet.Range("A3:A6")
rows = r.rows.Count
For i = rows To 1 Step (-1)
If WorksheetFunction.CountA(r.rows(i)) = 0 Then r.rows(i).Delete
Next
End Sub
It works even if we use Application instead of WorksheetFunction
If If Application.CountA(Range("A3:A6")) = 0 Then is not working as Tim suggested then that means the cells have blank spaces or unprintable characters.
Try this
Sub Sample()
Dim pos As Long
With Sheets("I- ABC")
pos = Len(Trim(.Range("A3").Value)) + _
Len(Trim(.Range("A4").Value)) + _
Len(Trim(.Range("A5").Value)) + _
Len(Trim(.Range("A6").Value))
If pos = 0 Then
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
Else
MsgBox "The cells are not empty"
End If
End With
End Sub
With skkakkar's idea expanded.
Sub Hello()
Dim rng As Range
Application.DisplayAlerts = 0
On Error GoTo er
Set rng = Range("A3:A6").SpecialCells(xlCellTypeConstants, 23)
Exit Sub
er: MsgBox "ActiveSheet.Delete" 'delete sheet
End Sub
If the spaces are the issue, then you can try this code:
Public Sub RemoveIfEmpty()
Application.DisplayAlerts = False
With Sheets("I- ABC")
If Trim(.Range("A3") & .Range("A4") & .Range("A5") & .Range("A6")) = "" Then
.Delete
End If
End With
Application.DisplayAlerts = True
End Sub