调用存储在 .xlam 文件中的 UDF 的 Evaluate() 函数并使其作用于另一张纸

Posted

技术标签:

【中文标题】调用存储在 .xlam 文件中的 UDF 的 Evaluate() 函数并使其作用于另一张纸【英文标题】:Calling Evaluate() function of a UDF stored in an .xlam file and making it act on another sheet 【发布时间】:2019-09-16 03:36:27 【问题描述】:

我编写了一个 UDF 来检查和计算条件格式的单元格颜色。 更新完整代码如下。

Function CountCellColor(RangeToCount As Range, ColorCell As Range, _
                                           LookupType As String) As Long
'Count the number of cells in range_data that has the same color _
 as the criteria cell, including both natural and conditional formatting _
 colors. If LookpType is "cell" then it will compare cell background _
 colors, if "font" then it will compare font colors.

Dim CFFormula As String
Dim CFCell As Range
Dim CellCounter As Double
Dim CFColor As Long
Dim i, j, k As Integer

CellCounter = 0

If LookupType = "cell" Then
    CFColor = ColorCell.Interior.Color

    For i = 1 To RangeToCount.Columns.Count 'Loop thru each cell
        For j = 1 To RangeToCount.Rows.Count
            Set CFCell = RangeToCount.Cells(j, i)
            If CFCell.Interior.Color = ColorCell.Interior.Color Then 'If the natural color matches then skip right to count that cell
                GoTo CountCellColor
            Else
                For k = 1 To CFCell.FormatConditions.Count 'Otherwise check each condition format of that cell
                    If CFCell.FormatConditions(k).Interior.Color = CFColor Then 'if the conditionned color match then check the formula
                        CFFormula = CFCell.FormatConditions(k).Formula1
                        CFFormula = Application.ConvertFormula(CFFormula, xlA1, xlR1C1)
                        CFFormula = Application.ConvertFormula(CFFormula, xlR1C1, xlA1, , ActiveCell.Resize(RangeToCount.Rows.Count, RangeToCount.Columns.Count).Cells(j, 1)) 'shifts to the next cell below in the conditionally formatted column
                        If Evaluate(CFFormula) = True Then  'if the formula evaluates to true then count that cell. Needs reference to ActiveCell cuz the macro is stored in a different file
CountCellColor:
                            CellCounter = CellCounter + 1
                        End If
                    End If
                Next k
            End If
        Next j
    Next i

ElseIf LookupType = "font" Then
    CFColor = ColorCell.Font.Color

    For i = 1 To RangeToCount.Columns.Count 'Loop thru each cell
        For j = 1 To RangeToCount.Rows.Count
            Set CFCell = RangeToCount.Cells(j, i)
            If CFCell.Font.Color = ColorCell.Font.Color Then 'If the natural color matches then skip right to count that cell
                GoTo CountFontColor
            Else
                For k = 1 To CFCell.FormatConditions.Count 'Otherwise check each condition format of that cell
                    If CFCell.FormatConditions(k).Font.Color = CFColor Then 'if the conditionned color match then check the formula
                        CFFormula = CFCell.FormatConditions(k).Formula1
                        CFFormula = Application.ConvertFormula(CFFormula, xlA1, xlR1C1)
                        CFFormula = Application.ConvertFormula(CFFormula, xlR1C1, xlA1, , ActiveCell.Resize(RangeToCount.Rows.Count, RangeToCount.Columns.Count).Cells(j, 1)) 'shifts to the next cell below in the conditionally formatted column
                        If Evaluate(CFFormula) = True Then 'if the formula evaluates to true the count that cell
CountFontColor:
                            CellCounter = CellCounter + 1
                        End If
                    End If
                Next k
            End If
        Next j
    Next i

Else
    CountCellColor = -1
    Exit Function
End If

CountCellColor = CellCounter

End Function

我已经测试过这适用于这些情况:

    UDF 存储在文件 A 中,UDF 在文件 A 表 1 中调用,目标 范围在文件 A 表 1 中 UDF 存储在文件 A 中,UDF 在文件 A 表 1 中调用,目标范围在文件 A 表 2 中 UDF 存储在加载的 .xlam 文件中,UDF 在文件 A sheet 1 中调用,目标范围也在文件 A sheet 1 中(图 1)

下面这1个案例不起作用 1. UDF存储在加载的.xlam文件中,UDF在文件A sheet 1中被调用,目标范围在文件A sheet 2中

现在,UDF 不返回任何错误,但它只是将 Evaluate(CFFormula) 行评估为 FALSE,并且不增加计数。

我在这样的结构化表格上调用它:

=CountCellColor(LDL1P1[EDL1 Need Trans],$I$5,"cell")

要评估的公式只是 A2="aaa"。所以这真的取决于这个 evaluate() 函数在哪里执行。应该在与 RangeToCount 相同的工作表中完成此操作。

【问题讨论】:

看来Evaluate(CFFormula)工作不正常(可能是长度?)检查docs.microsoft.com/en-us/office/vba/api/… Evaluate 公式适用于前 3 个案例。在最后一种情况下,它可能指的是错误的工作簿。所以我需要引用找到 RangeToCount 的工作表来调用 Evaluate()。 没有更多信息,不可能知道它是如何工作的……给我们看一个“CFFormula”示例 我怀疑这不是正确的 UDF。似乎调用全局变量(标准调用Option Explicit!),甚至可能尝试修改单元格(ConvertFormula:转换公式中的单元格引用)。因此,无论代码在技术上多么正确,它总是会返回错误。 我更新了 OP 人员。请再读一遍。谢谢! @AJD 这个 UDF 在我提到的 3 种情况下都能正常工作。 【参考方案1】:

我认为 Evaluate() 将始终在活动表上运行。因此,如果您需要它在另一张纸上运行,则需要指定。

RangeToCount.Parent.Evaluate(CFFormula)

【讨论】:

【参考方案2】:

这里有几个问题加剧了您的问题

    Evaluate(它自己)是 Application.Evaluate 的快捷方式,它在 Active Sheet 的上下文中调用。使用工作表舀版。 您使用ConvertFormula 抵消CF 公式的代码并非在所有情况下都有效。它也与活动工作表相关联,如果条件格式范围未与包含CountCellColor 公式的单元格对齐,则它根本不起作用。 虽然不是您的问题,但像这样使用 GoTo 确实是一种不好的做法 自然色细胞计数,只有在颜色未被 CF'g 改变的情况下才应计数 RangeToCount 可能包含多个不同的 CF 区域,因此需要考虑到这一点 此代码仅适用于表达式类型 CF'g,因此对此进行测试 其他小的改进机会(见下面的代码)

你的代码,重构

Function CountCellColor( _
  RangeToCount As Range, _
  ColorCell As Range, _
  LookupType As String) As Long
'Count the number of cells in range_data that has the same color _
 as the criteria cell, including both natural and conditional formatting _
 colors. If LookpType is "cell" then it will compare cell background _
 colors, if "font" then it will compare font colors.

 'Only counts Natural colored cells, if they are not colored by CF'g

    Dim CFFormula As String
    Dim CFCell As Range
    Dim CellCounter As Long '<~~~ you are counting, so use an int type
    Dim CFColor As Long
    Dim Rng As Range, cl As Range
    Dim CountedCell As Boolean
    Dim FC As FormatCondition

    CellCounter = 0

    If StrComp(LookupType, "cell", vbTextCompare) = 0 Then '<~~~ case insensitive
        CFColor = ColorCell.Interior.Color

        For Each CFCell In RangeToCount.Cells  '<~~~ Loop thru each cell
            CountedCell = False
            For Each FC In CFCell.FormatConditions   'check each conditional format of that cell
                If FC.Type = xlExpression Then
                    'shifts to the next cell below in the conditionally formatted column.
                    'Must be in the context of the passed range and its worksheet
                    Set Rng = FC.AppliesTo.Cells(1, 1)
                    CFFormula = FC.Formula1
                    CFFormula = Application.ConvertFormula(CFFormula, xlA1, xlR1C1, False, Rng)
                    CFFormula = Application.ConvertFormula(CFFormula, xlR1C1, xlA1, False, CFCell)

                    If RangeToCount.Worksheet.Evaluate(CFFormula) = True Then
                    'if the formula evaluates to true then consider that cell.
                        CountedCell = True
                        If FC.Interior.Color = CFColor Then
                        'if the conditionned color match then count
                            CellCounter = CellCounter + 1
                        End If
                    End If
                End If
            Next
            ' Only count base color cells that are not colored by CF
            If Not CountedCell Then
                If CFCell.Interior.Color = CFColor Then
                    CellCounter = CellCounter + 1
                End If
            End If
        Next

    ElseIf StrComp(LookupType, "font", vbTextCompare) = 0 Then
        ' similar

    Else
        CountCellColor = -1
    End If

    CountCellColor = CellCounter

End Function

也就是说,有一个更简单的方法 - 如果您有支持 DisplayFormat 的足够晚版本的 Excel(Excel 2010 或更高版本)

Function CountCellColor2( _
  RangeToCount As Range, _
  ColorCell As Range, _
  LookupType As String) As Long

    Dim cl As Range
    Dim MatchColor As Long
    Dim CellCounter As Long

    If StrComp(LookupType, "cell", vbTextCompare) = 0 Then
        MatchColor = ColorCell.Interior.Color
        For Each cl In RangeToCount.Cells
            If cl.DisplayFormat.Interior.Color = MatchColor Then
                CellCounter = CellCounter + 1
            End If
        Next
    ElseIf StrComp(LookupType, "font", vbTextCompare) = 0 Then
        MatchColor = ColorCell.Font.Color
        For Each cl In RangeToCount.Cells
            If cl.DisplayFormat.Font.Color = MatchColor Then
                CellCounter = CellCounter + 1
            End If
        Next
    End If
    CountCellColor2 = CellCounter
End Function

【讨论】:

以上是关于调用存储在 .xlam 文件中的 UDF 的 Evaluate() 函数并使其作用于另一张纸的主要内容,如果未能解决你的问题,请参考以下文章

从 Personal.xlam 工作簿调用函数

通过超链接公式调用另一个 XLAM 中的函数 - Excel VBA

VBA从添加到工作簿中导入udf模块

XLAM / XLA Addins:有更好的方法吗?

xlam Excel 插件是不是可以覆盖工作簿中的子项?

使用来自加载项用户定义函数 (UDF) 的数据填充 Excel 多个单元格