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 .Cells.value=empty For c = 0 To rs.Fields.Count - 1 .Cells(1, c + 1) = rs.Fields(c).name Next .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"")" db.close end sub sub test() buildTable populateSheet 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
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.
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
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 populateSheet 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 Else columnCriteria2(ctr) = Null End If Else columnCriteria1(ctr) = Null End If End With Next ctr End With 'clear autofilter sht.AutoFilterMode = False populateSheet '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 Else .AutoFilter Field:=ctr, Criteria1:=columnCriteria1(ctr), Criteria2:=columnCriteria2(ctr), Operator:=columnOperators(ctr) End If End If Next 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.