如何通过在单元格中输入文本来过滤 Table?
How to filter Table by entering text in cells?
我创建了一个 table 并且我只想过滤 33 列中的 4 列。
我所做的是分配了 5 个单元格(CountryName、ClientName、ProjNo 和 Date(frmDate - ToDate))。在其中一个单元格中输入文本时,需要过滤 table,然后按一个按钮清除单元格和 table.
的过滤器
我面临两个问题:
当我按下清除按钮时,只有单元格被清除,table没有。
我输入国名的时候,table中的获奖日期也被过滤了,不知道为什么也被过滤了
注意:如果有更好的VBA代码通过在这些单元格中输入来过滤table,也很好。
工作表 1 的屏幕截图(过滤单元格和 Table):
模块(FilteringModule):
Option Explicit
Sub TableFill()
Dim CountryName, ClientName, ProjNo As String
Dim ToDate, FrDate As Date
Dim MaxAmount, MinAmount As Integer
Dim LastRow As Long
With Sheet1
LastRow = .Range("G99999").End(xlUp).Row
If LastRow < 7 Then LastRow = 7
If .Range("E7").Value = "Enter BV Country" Then CountryName = Empty Else: CountryName = .Range("E7").Value 'Country Name'
If .Range("E9").Value = "Enter Client Name" Then ClientName = Empty Else: ClientName = .Range("E9").Value 'Client Name'
If .Range("E11").Value = "Enter Proj No." Then ProjNo = Empty Else: ProjNo = .Range("E11").Value 'Proj Name'
If .Range("E15").Value = "From Date" Then FrDate = "1/1/1900" Else: FrDate = .Range("E15").Value 'Date from'
If .Range("E16").Value = "To Date" Then ToDate = "1/1/2030" Else: ToDate = .Range("E16").Value 'Date To'
.Range("G6:AN" & LastRow).Select
Selection.AutoFilter
With .Range("G6:AN" & LastRow)
If CountryName <> Empty Then .AutoFilter Field:=2, Criteria1:="=*" & CountryName & "*"
If ClientName <> Empty Then .AutoFilter Field:=3, Criteria1:="=*" & ClientName & "*"
If ProjNo <> Empty Then .AutoFilter Field:=5, Criteria1:="=*" & ProjNo & "*"
.AutoFilter Field:=7, Criteria1:=">=" & FrDate, Operator:=xlAnd, Criteria2:="<=" & ToDate
End With
End With
End Sub
Sub ClearFilter()
With Sheet1
.Range("B4").Value = True
.AutoFilterMode = False
.Range("E7").Value = "Enter BV Country"
.Range("E9").Value = "Enter Client Name"
.Range("E11").Value = "Enter Proj No."
.Range("E15").Value = "From Date"
.Range("E16").Value = "To Date"
.Range("B4").Value = False
End With
End Sub
Sheet1 代码:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("E7,E9,E11,E15:E16")) Is Nothing And Range("B4").Value = False Then
TableFill
End If
End Sub
对您的代码的一些建议:
- 始终将变量命名为有意义的名称,例如
fromDate
而不是 frDate
- 至少使用基本的错误处理
On error Goto
- 看看我是如何按步骤划分逻辑的(可以做得更进一步,但你明白了)
- 这一行:
Dim CountryName, ClientName, ProjNo As String
只有 ProjNo 声明为字符串,其余为变体(所有变量都应为 As String
)
- 可以参考
ListObject
(table),它的范围不需要lastRow
- 最后,考虑将您的过滤器移动到另一个范围,当您应用它们时,它们会被隐藏
将您的工作表代码替换为:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.Range("E7,E9,E11,E15:E16")) Is Nothing Then
' Call the filter table procedure
filterTable Me
End If
End Sub
模块代码:
Option Explicit
Public Sub clearTableFilters()
On Error GoTo CleanFail
' Disable events so the filter table is not triggered everytime you change the filters' values
Application.EnableEvents = False
' Set default values
With Sheet1
.Range("E7").Value = "Enter BV Country"
.Range("E9").Value = "Enter Client Name"
.Range("E11").Value = "Enter Proj No."
.Range("E15").Value = "From Date"
.Range("E16").Value = "To Date"
End With
' Filter table
filterTable Sheet1
CleanExit:
' Reenable events
Application.EnableEvents = True
Exit Sub
CleanFail:
MsgBox "Error: " & Err.Description
GoTo CleanExit
End Sub
Public Sub filterTable(ByVal sourceSheet As Worksheet)
On Error GoTo CleanFail
' Get filter values
With sourceSheet
Dim countryName As String
countryName = .Range("E7").Value
Dim clientName As String
clientName = .Range("E9").Value
Dim projectNo As String
projectNo = .Range("E11").Value
Dim fromDate As Variant
fromDate = .Range("E15").Value
Dim toDate As Variant
toDate = .Range("E16").Value
End With
' Check if it's applying filters
Dim applyCountryFilter As Boolean
applyCountryFilter = getFilterStatus(countryName, "Enter BV Country", 1)
Dim applyClientNameFilter As Boolean
applyClientNameFilter = getFilterStatus(clientName, "Enter Client Name", 1)
Dim projectNoFilter As Boolean
projectNoFilter = getFilterStatus(projectNo, "Enter Proj No.", 1)
Dim fromDateFilter As Boolean
fromDateFilter = getFilterStatus(fromDate, "From Date", 2)
Dim toDateFilter As Boolean
toDateFilter = getFilterStatus(toDate, "To Date", 2)
Dim applyRemoveFilters As Boolean
applyRemoveFilters = (applyCountryFilter Or applyClientNameFilter Or projectNoFilter Or fromDateFilter Or toDateFilter)
' Define table to be filtered
Dim targetTable As ListObject
Set targetTable = Range("Table1").ListObject
' Select if applying or removing filters
Select Case applyRemoveFilters
Case True ' Apply
' Apply string filters
If applyCountryFilter Then applyRemoveAutoFilter targetTable, 2, applyCountryFilter, "*" & countryName & "*"
If applyClientNameFilter Then applyRemoveAutoFilter targetTable, 3, applyClientNameFilter, "*" & clientName & "*"
If projectNoFilter Then applyRemoveAutoFilter targetTable, 5, projectNoFilter, "*" & projectNo & "*"
' Apply date filters
Select Case True
Case (fromDateFilter And toDateFilter)
targetTable.Range.AutoFilter Field:=7, Criteria1:=">=" & fromDate, Operator:=xlAnd, Criteria2:="<=" & toDate
Case (fromDateFilter = True And toDateFilter = False)
targetTable.Range.AutoFilter Field:=7, Criteria1:=">=" & fromDate
Case (fromDateFilter = False And toDateFilter = True)
targetTable.Range.AutoFilter Field:=2, Criteria1:="<=" & toDate
Case Else
targetTable.Range.AutoFilter Field:=7
End Select
Case False ' Remove
targetTable.AutoFilter.ShowAllData
End Select
CleanExit:
Exit Sub
CleanFail:
MsgBox "Error: " & Err.Description
GoTo CleanExit
End Sub
Private Function getFilterStatus(ByVal fieldValue As Variant, ByVal fieldDefaultValue As String, ByVal filterType As Long) As Boolean
Select Case filterType
Case 1 ' String
getFilterStatus = Not (fieldValue = vbNullString Or LCase(fieldValue) = LCase(fieldDefaultValue))
Case 2 ' Date
getFilterStatus = Not (Not IsDate(fieldValue) Or ((IsDate(fieldValue) And fieldValue = 0)) Or LCase(fieldValue) = LCase(fieldDefaultValue))
End Select
End Function
Private Function getFilterDate(ByVal sourceDate As Variant) As Date
Select Case IsDate(sourceDate)
Case True
getFilterDate = sourceDate
Case False
getFilterDate = 0
End Select
End Function
Private Sub applyRemoveAutoFilter(ByVal targetTable As ListObject, ByVal columnNo As Long, ByVal applyFilter As Boolean, Optional ByVal criteriaValue As Variant)
Select Case applyFilter
Case True
targetTable.Range.AutoFilter Field:=columnNo, Criteria1:=criteriaValue
Case False
targetTable.Range.AutoFilter Field:=columnNo
End Select
End Sub
调整清除过滤器按钮以调用 clearTableFilters
过程
如果有效请告诉我
我创建了一个 table 并且我只想过滤 33 列中的 4 列。
我所做的是分配了 5 个单元格(CountryName、ClientName、ProjNo 和 Date(frmDate - ToDate))。在其中一个单元格中输入文本时,需要过滤 table,然后按一个按钮清除单元格和 table.
的过滤器我面临两个问题:
当我按下清除按钮时,只有单元格被清除,table没有。
我输入国名的时候,table中的获奖日期也被过滤了,不知道为什么也被过滤了
注意:如果有更好的VBA代码通过在这些单元格中输入来过滤table,也很好。
工作表 1 的屏幕截图(过滤单元格和 Table):
模块(FilteringModule):
Option Explicit
Sub TableFill()
Dim CountryName, ClientName, ProjNo As String
Dim ToDate, FrDate As Date
Dim MaxAmount, MinAmount As Integer
Dim LastRow As Long
With Sheet1
LastRow = .Range("G99999").End(xlUp).Row
If LastRow < 7 Then LastRow = 7
If .Range("E7").Value = "Enter BV Country" Then CountryName = Empty Else: CountryName = .Range("E7").Value 'Country Name'
If .Range("E9").Value = "Enter Client Name" Then ClientName = Empty Else: ClientName = .Range("E9").Value 'Client Name'
If .Range("E11").Value = "Enter Proj No." Then ProjNo = Empty Else: ProjNo = .Range("E11").Value 'Proj Name'
If .Range("E15").Value = "From Date" Then FrDate = "1/1/1900" Else: FrDate = .Range("E15").Value 'Date from'
If .Range("E16").Value = "To Date" Then ToDate = "1/1/2030" Else: ToDate = .Range("E16").Value 'Date To'
.Range("G6:AN" & LastRow).Select
Selection.AutoFilter
With .Range("G6:AN" & LastRow)
If CountryName <> Empty Then .AutoFilter Field:=2, Criteria1:="=*" & CountryName & "*"
If ClientName <> Empty Then .AutoFilter Field:=3, Criteria1:="=*" & ClientName & "*"
If ProjNo <> Empty Then .AutoFilter Field:=5, Criteria1:="=*" & ProjNo & "*"
.AutoFilter Field:=7, Criteria1:=">=" & FrDate, Operator:=xlAnd, Criteria2:="<=" & ToDate
End With
End With
End Sub
Sub ClearFilter()
With Sheet1
.Range("B4").Value = True
.AutoFilterMode = False
.Range("E7").Value = "Enter BV Country"
.Range("E9").Value = "Enter Client Name"
.Range("E11").Value = "Enter Proj No."
.Range("E15").Value = "From Date"
.Range("E16").Value = "To Date"
.Range("B4").Value = False
End With
End Sub
Sheet1 代码:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("E7,E9,E11,E15:E16")) Is Nothing And Range("B4").Value = False Then
TableFill
End If
End Sub
对您的代码的一些建议:
- 始终将变量命名为有意义的名称,例如
fromDate
而不是frDate
- 至少使用基本的错误处理
On error Goto
- 看看我是如何按步骤划分逻辑的(可以做得更进一步,但你明白了)
- 这一行:
Dim CountryName, ClientName, ProjNo As String
只有 ProjNo 声明为字符串,其余为变体(所有变量都应为As String
) - 可以参考
ListObject
(table),它的范围不需要lastRow - 最后,考虑将您的过滤器移动到另一个范围,当您应用它们时,它们会被隐藏
将您的工作表代码替换为:
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Me.Range("E7,E9,E11,E15:E16")) Is Nothing Then
' Call the filter table procedure
filterTable Me
End If
End Sub
模块代码:
Option Explicit
Public Sub clearTableFilters()
On Error GoTo CleanFail
' Disable events so the filter table is not triggered everytime you change the filters' values
Application.EnableEvents = False
' Set default values
With Sheet1
.Range("E7").Value = "Enter BV Country"
.Range("E9").Value = "Enter Client Name"
.Range("E11").Value = "Enter Proj No."
.Range("E15").Value = "From Date"
.Range("E16").Value = "To Date"
End With
' Filter table
filterTable Sheet1
CleanExit:
' Reenable events
Application.EnableEvents = True
Exit Sub
CleanFail:
MsgBox "Error: " & Err.Description
GoTo CleanExit
End Sub
Public Sub filterTable(ByVal sourceSheet As Worksheet)
On Error GoTo CleanFail
' Get filter values
With sourceSheet
Dim countryName As String
countryName = .Range("E7").Value
Dim clientName As String
clientName = .Range("E9").Value
Dim projectNo As String
projectNo = .Range("E11").Value
Dim fromDate As Variant
fromDate = .Range("E15").Value
Dim toDate As Variant
toDate = .Range("E16").Value
End With
' Check if it's applying filters
Dim applyCountryFilter As Boolean
applyCountryFilter = getFilterStatus(countryName, "Enter BV Country", 1)
Dim applyClientNameFilter As Boolean
applyClientNameFilter = getFilterStatus(clientName, "Enter Client Name", 1)
Dim projectNoFilter As Boolean
projectNoFilter = getFilterStatus(projectNo, "Enter Proj No.", 1)
Dim fromDateFilter As Boolean
fromDateFilter = getFilterStatus(fromDate, "From Date", 2)
Dim toDateFilter As Boolean
toDateFilter = getFilterStatus(toDate, "To Date", 2)
Dim applyRemoveFilters As Boolean
applyRemoveFilters = (applyCountryFilter Or applyClientNameFilter Or projectNoFilter Or fromDateFilter Or toDateFilter)
' Define table to be filtered
Dim targetTable As ListObject
Set targetTable = Range("Table1").ListObject
' Select if applying or removing filters
Select Case applyRemoveFilters
Case True ' Apply
' Apply string filters
If applyCountryFilter Then applyRemoveAutoFilter targetTable, 2, applyCountryFilter, "*" & countryName & "*"
If applyClientNameFilter Then applyRemoveAutoFilter targetTable, 3, applyClientNameFilter, "*" & clientName & "*"
If projectNoFilter Then applyRemoveAutoFilter targetTable, 5, projectNoFilter, "*" & projectNo & "*"
' Apply date filters
Select Case True
Case (fromDateFilter And toDateFilter)
targetTable.Range.AutoFilter Field:=7, Criteria1:=">=" & fromDate, Operator:=xlAnd, Criteria2:="<=" & toDate
Case (fromDateFilter = True And toDateFilter = False)
targetTable.Range.AutoFilter Field:=7, Criteria1:=">=" & fromDate
Case (fromDateFilter = False And toDateFilter = True)
targetTable.Range.AutoFilter Field:=2, Criteria1:="<=" & toDate
Case Else
targetTable.Range.AutoFilter Field:=7
End Select
Case False ' Remove
targetTable.AutoFilter.ShowAllData
End Select
CleanExit:
Exit Sub
CleanFail:
MsgBox "Error: " & Err.Description
GoTo CleanExit
End Sub
Private Function getFilterStatus(ByVal fieldValue As Variant, ByVal fieldDefaultValue As String, ByVal filterType As Long) As Boolean
Select Case filterType
Case 1 ' String
getFilterStatus = Not (fieldValue = vbNullString Or LCase(fieldValue) = LCase(fieldDefaultValue))
Case 2 ' Date
getFilterStatus = Not (Not IsDate(fieldValue) Or ((IsDate(fieldValue) And fieldValue = 0)) Or LCase(fieldValue) = LCase(fieldDefaultValue))
End Select
End Function
Private Function getFilterDate(ByVal sourceDate As Variant) As Date
Select Case IsDate(sourceDate)
Case True
getFilterDate = sourceDate
Case False
getFilterDate = 0
End Select
End Function
Private Sub applyRemoveAutoFilter(ByVal targetTable As ListObject, ByVal columnNo As Long, ByVal applyFilter As Boolean, Optional ByVal criteriaValue As Variant)
Select Case applyFilter
Case True
targetTable.Range.AutoFilter Field:=columnNo, Criteria1:=criteriaValue
Case False
targetTable.Range.AutoFilter Field:=columnNo
End Select
End Sub
调整清除过滤器按钮以调用 clearTableFilters
过程
如果有效请告诉我