【问题标题】:VBA Go to the next filtered cellVBA 转到下一个过滤的单元格
【发布时间】:2015-10-14 02:46:59
【问题描述】:

我目前正在使用以下代码:

Sub SendEmail()

    Dim objOutlook As Object
    Dim objMail As Object
    Dim RowsCount As Integer
    Dim Index As Integer
    Dim Recipients As String
    Dim Category As String
    Dim CellReference As Integer

    Set objOutlook = CreateObject("Outlook.Application")
    Set objMail = objOutlook.CreateItem(0)

    If ActiveSheet.FilterMode = True Then
        RowsCount = ActiveSheet.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count - 1
    ElseIf ActiveSheet.FilterMode = False Then
        RowsCount = Application.CountA(Range("A2:A" & Rows.Count)) - 1
    End If

    ' In Range("I1") there is the job category the user wants to email
    Category = Range("I1")
    If Category = Range("S2") Then
        ' CellReference is the amount of columns to the right of column A, ie Column A is 0 so CellReference below is J - which is the column location of the email address according to that category
        CellReference = 10
    ElseIf Category = Range("S3") Then
        CellReference = 14
    ElseIf Category = Range("S4") Then
        CellReference = 18
    ElseIf Category = Range("S5") Then
         CellReference = 16
    End If

    Index = 0
    While Index < RowsCount
        Set EmailAdrs = ActiveSheet.AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).Cells(1, CellReference).Offset(0 + Index, 0)
        Recipients = Recipients & EmailAdrs.Value & ";"
        Index = Index + 1
    Wend

     With objMail
        .To = Recipients
        .Subject = "This is the subject"
        .Display
    End With

    Set objOutlook = Nothing
    Set objMail = Nothing

End Sub

此代码检查是否已应用过滤器并计算行数(如果有或没有),然后检查应向谁发送电子邮件(I1 中的“类别”是不同个人的工作职位),然后获取所需人员的电子邮件地址,我遇到的问题是我有以下数据(这只是我想做的一个例子):

Column A         Column B             Column C
Smith            Male                 123@123.co.uk
Jones            Male                 abc@abc.co.uk
Smith            Female               456@123.co.uk
Jones            Female               def@abc.co.uk
Smith            Male                 789@123.co.uk
Smith            Female               101112@123.co.uk
Smith            Female               141516@123.co.uk
Jones            Female               ghi@abc.co.uk

我过滤 A 列中的 Jones 和 B 列中的 Female 以返回两行,而不是获取电子邮件地址 def@abc.co.ukghi@abc.co.uk 它将获得电子邮件地址 def@abc.co.uk 和 @ 987654329@,因为它找到应用了过滤器的第一行,然后忽略过滤器进入下一个单元格。

有什么方法可以解决这个问题,以便获得过滤后的单元格?

重要的是要指出过滤器可能并不总是相同的,因此它不会总是同时是 A 列和 B 列,它可能只是 A 列或只是 B 列。

【问题讨论】:

  • 我不擅长过滤器,但我认为您始终可以在 A 列上循环,如果您找到包含 Jones 的单元格,则将该单元格 (,2) 添加到 Recipients。
  • 当推到紧要关头时,如果您要遍历可见行,是否有活动过滤器有什么区别?重要的是有几行要经过。
  • @Jeeped 你指的是以下几行:If ActiveSheet.FilterMode = True Then?
  • 是的。非 .FilterMode 代码不仅看起来很可疑,而且真的没有任何意义来写两个。如果没有 .FilterMode 则所有行都将可见。如果有,那么只有一些行是可见的。如果您为可见行编写例程,那么是否存在 FilterMode 有什么区别?
  • 它根本没有任何区别,它只是帮助我看到它正在计算正确的行,这意味着当While Index &lt; RowsCount 行运行时,我不必坐下来使用调试器通过大量记录。但你说得对,那里不需要它。

标签: vba excel loops while-loop


【解决方案1】:

将代码的底部替换为:

If ActiveSheet.FilterMode = True Then
    With ActiveSheet.AutoFilter.Range
        For Each a In .Offset(1).Resize(.Rows.Count).SpecialCells(xlCellTypeVisible).Areas
            Recipients = Recipients & a(1, CellReference) & ";"
        Next
    End With
    MsgBox Replace(Recipients, ";;", vbNullString)
End If

【讨论】:

    【解决方案2】:

    你可以使用

    1) 选择范围:(当然可以用公式代替固定范围)

    Dim Rng As Range
    If Category = Range("S2") Then
        ' CellReference is the amount of columns to the right of column A, ie Column A is 0 so CellReference below is J - which is the column location of the email address according to that category
        CellReference = 10
        'Set your range
        Set Rng = [Insert here your criteria to set the range when CellReference = 10]
    
    ElseIf Category = Range("S3") Then
        CellReference = 14
        'Set your range
        Set Rng = [Insert here your criteria to set the range when CellReference = 14]
    ElseIf Category = Range("S4") Then
        CellReference = 18
        'Set your range
        Set Rng = [Insert here your criteria to set the range when CellReference = 18]
    ElseIf Category = Range("S5") Then
         CellReference = 16
        'Set your range
        Set Rng = [Insert here your criteria to set the range when CellReference = 16]
    End If
    

    (考虑使用Select Case 而不是ElseIf) 然后循环范围

    'You need to replace YourSheetName with the real name of your sheet
    For Each mCell In ThisWorkbook.Sheets("YourSheetName").Range(Rng).SpecialCells(xlCellTypeVisible)
        'Get cell address
        mAddr = mCell.Address
        'Get the address of the cell on the column you need
        NewCellAddr = mCell.Offset(0, ColumnsOffset).Address
        'Do everything you need
    Next mCell
    

    mCell 是一个对象变量,其中包含有关它所代表的单元格的大量信息。

    所以,如果 mCell 是包含“Hello World”的 A1 Cell:

    mCell.Address will be "$A$1"
    mCell.Value will be "Hello World"
    mCell.Offset(0, 2).Address will be "$C$1"
    

    您还可以获取和/或设置许多其他数据:

    mCell.NumberFormat
    mCell.RowHeight
    mCell.Formula
    

    查看局部变量以了解您可以为 mCell 获取/设置的所有内容

    【讨论】:

    • 请注意,每次选择的类别不同,范围会有所不同,请参阅编辑后的问题。不过还是谢谢你的回答。
    • @BenSmith 我编辑了我的答案以建议如何修改您的代码
    • 感谢您的编辑,我对 VBA 不是很精通,所以您介意向我解释一下 For Each mCell In ThisWorkbook.Sheets("BM &amp; SM Contact List").Range(Rng).SpecialCells(xlCellTypeVisible)NewCellAddr = mCell.Offset(0, ColumnsOffset).Address 行的作用吗?特别是因为我不明白mCellColumnsOffset 是什么。在您的评论Do everything you need 之后,我会插入While Index &lt; RowsCount 以及它和Wend 之间的行吗?
    • 感谢您的回答和补充。但是,我的代码存在以下问题,当我运行它时它不起作用:首先,像Set Rng = Range("A1:B2") 这样的行不能真正工作,因为如果插入更多行数可能会改变,我也使用该行Each mCell In ThisWorkbook.Sheets("YourSheetName").Range(Rng).SpecialCells(xlCellTypeVisible) I get the error: 运行时错误“1004”:应用程序定义或对象定义错误。你能帮忙吗?
    • @BenSmith 我再次编辑。无论如何,如果您过滤数据并仅循环过滤数据,您确定需要不同的范围吗?如果您编辑您的问题并解释确定您需要的范围(或工作表上的数据)的标准,我会尽力为您提供一种方法。
    猜你喜欢
    • 2015-10-15
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-19
    • 2021-06-14
    • 1970-01-01
    相关资源
    最近更新 更多