Home » excel » excel – clear cells while preserving Autofilter settings?

excel – clear cells while preserving Autofilter settings?

Posted by: admin May 14, 2020 Leave a comment


I’m writing a script for a worksheet whose cells are populated based on an Access database. I’m trying to clear the contents of the worksheet without removing any Autofilters that the user has set, and then reload the data based on on the database. Right now I’m using:

Sub populateSheet()

Dim sht As Worksheet
Dim db As Database
Dim rs As Recordset

Set db = OpenDatabase("c:\myDB.mdb")
Set rs = db.OpenRecordset("myData")
Set sht = ThisWorkbook.Sheets("my output")
With sht
    For c = 0 To rs.Fields.Count - 1
        .Cells(1, c + 1) = rs.Fields(c).name
    .Range("a2").CopyFromRecordset rs
End With

End Sub

sub buildTable()

dim ws as workspace
dim db as database
dim dbPath as string

set ws=dbengine.workspaces(0)
set db=ws.createdatabase("c:\myDB.mdb")
db.execute "create table myData (field1 text,field2 text)"
db.execute "insert into myData (field1,field2) values (""1"",""a"")"
db.execute "insert into myData (field1,field2) values (""2"",""b"")"
db.execute "insert into myData (field1,field2) values (""3"",""a"")"


end sub
sub test()
end sub

When I run .cells.clear, it wipes out the Autofilter. Is there a way I can keep the Autofilter settings so the new data will be filtered the same way? Or maybe record them and re-apply the same settings? I tried working with this solution, but I had trouble getting it to detect which columns were filtered.


I applied Jean-FrançoisCorbett’s approach in the above code, but it has a problem. Try this with a test table:

1 a
2 b
3 a

After you run populateSheet, then autofilter the 2nd column to only include “a”, the worksheet shows:

1 a
3 a

Then run populateSheet again, the sheet now shows:

1 a
1 a

If you remove the autofilter, rerun populateSheet, and re-apply the autofilter, you get the correct data, but that’s a very cumbersome extra step to get correct output.

I added code to create a database and make a table that you can use to test populateSheet, and changed some of the arguments in populateSheet to reflect this test database.

How to&Answers:

If you just want to clear the values in the cells and nothing else, then you can do this:

sht.Cells.Value = Empty

EDIT Responding to the OP’s edit:

Oddly enough, the statement above does not empty the cells in any rows that were hidden by the Autofilter! I think that the autofilter-hidden rows also cause unexpected behaviour when importing data with CopyFromRecordset.

The solution to that problem is of course to, prior to emptying all cells and importing data, unhide all rows by setting the autofilters to (All), which in VBA is done like this:

With Range("C1:D1") ' or wherever the filters are
    .AutoFilter Field:=1
    .AutoFilter Field:=2
    ' ... continue to set all fields to (All).
End With


Ok, I have a solution for this. Basically, I record the autofilter criteria in an array of variants, then remove the Autofilter settings, populate the sheet (using @Jean-FrançoisCorbett’s suggestion of sht.Cells.Value = Empty) then reapply the settings from the array. Code as follows:

Sub reapplyAutofilter()

Dim fltr As Filter
Dim columnCriteria1() As Variant
Dim columnCriteria2() As Variant
Dim columnOperators() As Variant

Dim filterCriteria() As Variant
Dim sht As Worksheet
Dim rangeAddr As String
Dim fieldCount As Long
Dim ctr As Long

Set sht = ThisWorkbook.Sheets("mySheet")

'don't analyze autofilter if it's not on
If Not sht.AutoFilterMode Then              
    Exit Sub
End If

'put autofilter settings in arrays for criteria1, criteria2, and operator    
With sht.AutoFilter
    rangeAddr = .Range.Address                 
    fieldCount = .Filters.Count
    ReDim columnCriteria1(1 To fieldCount)
    ReDim columnCriteria2(1 To fieldCount)
    ReDim columnOperators(1 To fieldCount)
    For ctr = 1 To fieldCount
        With .Filters(ctr)
            If .On Then
                columnCriteria1(ctr) = .Criteria1
                columnOperators(ctr) = .Operator
                If (.Operator = xlOr) or (.Operator=xlAnd) Then
                    columnCriteria2(ctr) = .Criteria2
                    columnCriteria2(ctr) = Null
                End If
                columnCriteria1(ctr) = Null
            End If
        End With
    Next ctr
End With

'clear autofilter     
sht.AutoFilterMode = False


're-apply autofilter settings    
With sht.Range(rangeAddr)
    For ctr = 1 To fieldCount
        If Not IsNull(columnCriteria1(ctr)) Then
            If IsNull(columnCriteria2(ctr)) Then
                .AutoFilter Field:=ctr, Criteria1:=columnCriteria1(ctr), Operator:=xlFilterValues
                .AutoFilter Field:=ctr, Criteria1:=columnCriteria1(ctr), Criteria2:=columnCriteria2(ctr), Operator:=columnOperators(ctr)
            End If
        End If
End With

End Sub

I’m not sure if this counts as me solving the problem, because I was inspired by Jean-FrançoisCorbett’s code. I did have to figure out on my own how to capture and reapply the Autofilter settings. Feel free to chime in about who should get credit on this one; otherwise, I’ll accept my own answer.