Excel VBA脚本意外过滤标头

时间:2016-08-10 19:31:54

标签: vba excel-vba excel

简介

我有一些电子表格,如下所示。

original data after script execution

此处标题位于第16行和第17行。在较早的行和列中,左侧有一个“标题”(未显示),包括图片,某些非表格数据,图例等。这里不重要。第16行上的标题文本被混淆,因为原因。以粗体红色标记的数据表示该采样点已经过一些处理。以下是脚本中的代码段,以粗体红色突出显示这些数据点。

' Traverse columns applying redding until hitting the row end, Comment, or SpGr: whichever comes first
For currIndex = abcDateCol + 1 To lastCol
  ' Check for exit conditions:
  If Cells(abcDateRowDesc, currIndex).Value() = "Comments" Then Exit For

  If Cells(abcDateRowDesc, currIndex).Value() <> "" Then
    If Cells(abcDateRowDesc, currIndex + 1).Value() = "process" Then
      ' Looks like we have a column of something Red-able
      Columns(ColumnLetter(currIndex) & ":" & ColumnLetter(currIndex + 1)).Select
      Selection.AutoFilter ' Turn on autofiltering (hopefully)
      Selection.AutoFilter Field:=2, Criteria1:="=1", Operator:=xlOr, Criteria2:="=e"
      Selection.Font.ColorIndex = 3
      Selection.Font.Bold = True
      Selection.AutoFilter ' Turn off autofiltering
      Columns(ColumnLetter(currIndex + 1) & ":" & ColumnLetter(currIndex + 1)).EntireColumn.Delete Shift:=xlToLeft
    End If
  End If
Next currIndex

上下文

此处,abcDateCol表示AE列,lastCol表示列AQ,abcDateRow(未显示,但可用),abcDateRowDesc表示标题行16和分别为17,ColumnLetter函数是用户定义的函数,它返回给定列号的人类可读列字母;这是你在其他地方看到的常见功能,甚至是你自己做的。

让我们继续

别介意If Cells(abcDateRowDesc, currIndex).Value() = "Comments"中的条件因疏忽而无法满足(我假设) - 保证两行不同。

让我们看一下在执行此脚本之前电子表格的样子。

original data before script execution

因此,脚本采用成对的列,并且对于每对列,如果数据单元的右邻单元格具有1(或“e”?)(作为布尔值;则回答问题,“这个样本点是否经历过任何过程?”)然后删除“过程”列。

问题

客户希望无偿的标题消失,因此他们可以更轻松地将电子表格导入到他们拥有的任何解决方案中。删除第1行到第15行,这就是我得到的。

enter image description here

标题中发生的哔哔声是什么?我不明白第一行是如何突出显示的。这似乎太奇怪了。现在,让我们重新审视第一个电子表格。

enter image description here

我在脚本执行后用一些虚拟文本填充了“标题”。哇,第一行再次变红,这次 ad infinitum !所以,这个问题一直存在。哦,第一栏也是!并且,它神奇地停在正确的标题之上,所以我们永远不会看到它。

问题

为什么此脚本意外地使第一行和列变红?这可以轻松解决,还是我在考虑某种重写?如果是这样,请指出我的方向。

值得一提的是,这些电子表格是从Windows应用程序生成的,并且在用户拥有电子表格副本之前执行其脚本。此外,关于第二张图片(显示“过程”列的电子表格),此电子表格不是通常存在的内容。我通过跳过脚本的for循环来为这篇文章生成它。该应用程序使用选定的电子表格模板,该模板看起来相同,减去数据,填写示例数据,然后对数据执行多个脚本。

我考虑使用条件格式,但有几十个电子表格模板。即使我只是改变了我需要的那个,我也无法改变这些常见脚本在其上运行的事实。我觉得我最好的选择是纠正脚本。并且,我不会更改脚本来解释我的边缘情况。整个生态系统感觉不稳定,但这只是主观的。

注意

我不是此脚本的作者(或我公司的任何VBA!)。我正在考虑这是对我征收的遗产税。

*更新

我被问到是否跟踪了这段代码。我很抱歉我没有在原帖中包含这些信息。这就是我所知道的。 Selection.Font.ColorIndex = 3转动选择中满足自动过滤器加第一行的单元格(两个单元格在给定时间仅选择两列),Selection.Font.Bold = True以相同方式使相同单元格变为粗体。我怀疑它与自动过滤器有关,所以我现在要看看答案。

2 个答案:

答案 0 :(得分:3)

这个编辑可以解决你的问题,希望(他们为我的电子表格重拍做了,但我们不会知道你试试真实的东西)

' Traverse columns applying redding until hitting the row end, Comment, or SpGr: whichever comes first
For currIndex = abcDateCol + 1 To lastCol
    ' Check for exit conditions:
    If Cells(abcDateRowDesc, currIndex).Value() = "Comments" Then Exit For

    If Cells(abcDateRowDesc, currIndex).Value() <> "" Then
        If Cells(abcDateRowDesc, currIndex + 1).Value() = "process" Then
            ' Looks like we have a column of something Red-able
            'Columns(ColumnLetter(currIndex) & ":" & ColumnLetter(currIndex + 1)).Select
            With Range(Cells(abcDateRowDesc, currIndex), Cells(abcDateRowDesc, currIndex + 1).End(xlDown))
                .AutoFilter 2, "=1", xlOr, "=e"
                ' Don't format header
                With .Offset(1, 0).Resize(.Rows.Count - 1, .Columns.Count)                         .Font.ColorIndex = 3
                    .Font.Bold = True
                    .AutoFilter ' Turn off autofiltering
                End With
            End With
            Columns(currIndex + 1).Delete xlShiftLeft
        End If
    End If
Next currIndex

这一切都始于代码如何选择自动过滤的范围。所选区域是完整列,而不是您实际要格式化的区域(第18行到最后一个条目)。似乎在具有空顶行的完整列上自动过滤会自动将第一个非空行设置为标题行。因此,标题未被过滤/取消隐藏,并且它将作为完整列选择的一部分着色。这就是你的标题变色的原因。

现在,如果您尝试通过将数据放入上述空行(例如“a”)来测试此值,那么这些值将成为列中的第一个值并将被选为标题 - 意味着那些值变为彩色。 您列中第一个非空行中的任何内容都将是自动过滤器标题,并且会变色。

但这应该只影响你明确着色的列,而不是第一行的整体,对吗?这里的问题是Excel喜欢对数据做出假设以节省时间。所以,如果你有一整行充满红色,粗体“a”并且紧挨着它们,你会放入另一个“a”来测试该单元格是否格式化......好吧,尽管单元格之前没有格式化,它会自动为您提供红色,粗体“a”!如果你继续以这种方式走下去,看起来你的整行都被格式化了。但是,如果你跳过几列(比如5-ish)并输入另一个“a”,瞧,它没有格式化,你放在它附近的任何“a”也是如此。您还可以通过删除远离列中未格式化的“a”来检查Excel,然后继续输入“a”,直到达到相同的单元格 - this时间,“a”将是红色和粗体,因为行中的所有其他人也是,即使我们只是检查这是一个未格式化的单元格!

基本上,为自动过滤器设置了错误的范围会使事情出乎意料地发生,然后尝试通过输入值来测试格式问题,这使得一切都变得不那么清晰。我提供的代码只是自动过滤相关区域(第17行到最后一个连续行),修复了核心问题。

答案 1 :(得分:1)

这是一个(注释)代码的重构,应该这样做:

Option Explicit

Sub main()
    Dim abcDateCol As Long, lastCol As Long, abcDateRow As Long, abcDateRowDesc As Long, currIndex As Long

    abcDateCol = 31
    lastCol = 43
    abcDateRow = 16 '<--| you can change it to 1 for the last "scenario"
    abcDateRowDesc = 17 '<--| you can change it to 2 for the last "scenario"


    For currIndex = abcDateCol + 1 To lastCol '<--| loop through columns
        With Cells(abcDateRow, currIndex) '<--| refer to cell in current column on row abcDateRow
            If .Value = "Comments" Then Exit For '<--| Check for exit conditions on row 'abcDateRow'

            If .Offset(1).Value <> "" And .Offset(1, 1).Value = "process" Then '<--| Check for processing conditions on row 'abcDateRowDesc'
                With .Resize(.Offset(, 1).End(xlDown).Row - .Row + 1, 2) '<-- consider the range from current referenced cell 1 column to the right and down to last 'process' number/letter
                    .AutoFilter Field:=2, Criteria1:="=1", Operator:=xlOr, Criteria2:="=e" '<--| filter on "process" field with "1" or "e"
                    If Application.WorksheetFunction.Subtotal(103, .Cells.Resize(, 1)) > 1 Then '<--| if any values match...
                        With .Offset(2).Resize(.Rows.Count - 2, 1).SpecialCells(xlCellTypeVisible).Font '<--|... consider only filtered values skipping headers (2 rows), and apply formatting
                            .ColorIndex = 3
                            .Bold = True
                        End With
                    End If
                    .AutoFilter '<-- reset autofilter
                    .Resize(, 1).Offset(, 1).EntireColumn.Delete Shift:=xlToLeft '<-- delete the "2nd" column (i.e. one column offsetted to the right)
                End With
            End If
        End With
    Next currIndex
End Sub

你的&#34;继承了#34;代码:

  • If Cells(abcDateRowDesc, currIndex).Value() = "Comments" Then Exit For将被引用到abcDateRow索引行

  • 格式化将应用于所有单元格,是否已过滤(匹配)