excel - 具有参数的Excel自定义函数

标签 excel vba function

我正在尝试在excel模块中创建一个自定义函数,如下所示:

Function STATUS(valuex As String)

    If ActiveCell.Offset(0, 1).Value = valuex Then

    ActiveCell.Value = ActiveCell.Offset(0, -1).Value

    'Remove value from left column
     Activecell.offset(0,1).clearcontents

   End If

End Function


它基本上会这样做:

Number  Result  Status
          11    System
22              Type
          33    System
          44    System
55              Hardware
66              Type
          77    System
          88    System
99              Software
110             Type
         121    System
         132    System
143             Hardware
154             Type
165             Type
         176    System
187             Hardware
198             Type
209             Software


如果右单元格= valuex(例如字符串“ System”)类似于valuex,则
将左单元格的值放在公式/函数单元格中,然后删除左列的值。

但是我编写的所有程序返回的都是零(0)或Name#错误。

请帮忙

最佳答案

您正在用公共标准模块编写用户定义函数(UDF),即Public Function,可以从工作表单元格中调用它-这种特定类型的函数具有特定的约束集。例如,不允许有副作用。 UDF接受一些输入,对其进行处理,然后返回结果。

因此,UDF的签名应如下所示:

Public Function {name}({args}) As {type}


编写函数时,首先要考虑的是返回它需要什么-换句话说,计算出=MYFUNCTION(A1,A2)的单元格应该包含什么。例如,如果您编写了一个Add函数,将两个Double值加在一起,则希望它返回一个Double

Public Function Add(ByVal value1 As Double, ByVal value2 As Double) As Double


函数的主体根据给定的参数计算结果:

    Dim result As Double
    result = value1 + value2


在返回/退出之前,您需要分配函数的返回值。这是通过分配给函数的标识符来完成的:

    Add = result


然后,Excel的计算引擎将获得该结果,这就是具有=Add(2, 2)之类的公式的单元格以4值结束的方式。



您的STATUS函数依赖于ActiveCell,这是ActiveSheet当前选择的任何单元格:不是调用该函数的单元格。如果选择了某些随机单元格,则重新计算工作簿可能会产生错误的结果。

作为UDF,不允许在某个单元格上使用.ClearContents(或以任何方式影响任何其他单元格)-这就是该函数为进入条件块的执行路径返回#NAME?错误的原因,并且没有分配返回值,其他执行路径产生0,这是Empty变量的数字表示,这是您的函数当前返回的内容。

如果UDF需要了解另一个单元格的值,则最好的办法是将该单元格的值作为参数:这样一来,该函数就可以工作,而无需任何关于工作表布局的假设。如果VLOOKUP不使用lookup_value参数,而是从.Offset(0, 1)单元格中获取该值,它将有多大用处?会有骚乱!



当您需要执行某项操作而不是计算/计算某些操作时,所需的不是UDF,而是宏。

宏是公共标准模块(或Public Sub模块)中的无参数Worksheet过程,可以从“宏”窗口调用该宏,也可以在用户单击ActiveX Shape CommandButton时执行>,或者可以将它们分配给某些自定义菜单项的OnAction属性-无论您的船摇动什么。

Sub程序做了一些事情,它们是动作。他们可以访问和更改全局状态,修改任何单元格,工作表或工作簿;他们甚至可以生成PowerPoint实例,然后将图表作为图片粘贴到新的Slide上-您可能会想到的一切都是天空的极限!

由于这里需要的是可以完成工作的东西,因此需要编写的代码必须更像是宏。不要称它为STATUS;使用动词并描述其作用:您正在根据给定的条件将值从一列移动到另一列。编写Sub过程时,请先考虑如何调用它。

我认为这样会很整洁:

MoveValues Sheet1.Range("$B$2:$B$22"), "System"


所以签名看起来像这样:

Private Sub MoveValues(ByVal Target As Range, ByVal Criteria As String)


现在,主体可以遍历指定的Target范围,评估右侧的单元格是否与Criteria匹配,然后相应地将值向左移动。或者更好-我们根本不假设工作表布局,而是这样调用它:

With Sheet1
    MoveValues .Range("A2:A22"), .Range("B2:B22"), .Range("C2:C22"), "System"
End With


现在,如果我们需要在A与B之间或B与C之间插入一列,我们只需要更改传递给过程的参数,而不是过程本身!

Private Sub MoveValues(ByVal Source As Range, ByVal Target As Range, ByVal Status As Range, ByVal Criteria As String)


但是首先,我们需要验证我们的假设,并确定在未达到期望值时该怎么做-我们需要行数相等的单列范围!

在许多情况下,最好是执行运行时错误。错误#5“无效的过程调用或参数”似乎很合适:

    If Source.Columns.Count <> 1 Or Target.Columns.Count <> 1 Or  Status.Columns.Count <> 1 Or _
       Source.Rows.Count <> Target.Columns.Count Or _
       Status.Rows.Count <> Target.Columns.Count _
    Then
        Err.Raise 5
    End If


我们甚至可以自定义错误消息,以帮助我们稍后调试调用代码,当我们在此行的6个月后更改参数并忘记有关该MoveValues过程的假设的所有信息时:

    If Source.Columns.Count <> 1 Or Target.Columns.Count <> 1 Or  Status.Columns.Count <> 1 Or _
       Source.Rows.Count <> Target.Columns.Count Or _
       Status.Rows.Count <> Target.Columns.Count _
    Then
        Err.Raise 5, "MoveValues", _
            "Source, Target, and Status ranges must be 1 column and the same number of rows."
    End If


我们还需要验证我们的Criteria不是空的还是空白!

    If Trim$(Criteria) = vbNullString Then
        Err.Raise 5, "MoveValues", "Criteria string cannot be empty or whitespace."
    End If


既然我们已经验证了输入,接下来的过程可以安全地假设SourceTargetStatus范围都是单列范围,并且它们都具有相同的大小,并且有效的标准。这样我们就可以迭代细胞并做我们的事情:

    Dim current As Long
    For current = 1 To Target.Rows.Count
        If Status.Cells(current).Value = Criteria Then
            Target.Cells(current).Value = Source.Cells(current).Value
            Source.Cells(current).ClearContents 
        End If
    Next


现在剩下要做的就是编写一个调用它的宏:

Public Sub MoveSystemValues()
    With Sheet1
        MoveValues .Range("A2:A22"), .Range("B2:B22"), .Range("C2:C22"), "System"
    End With
End Sub


现在我们可以从Excel的“宏”窗口运行该MoveSystemValues宏,或将MoveSystemValues分配给某些Shape或按钮...,然后意识到对于少量的行它可以很好地工作,但是给定的速度很慢范围更大-但我们现在有足够的咀嚼空间。

关于excel - 具有参数的Excel自定义函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52096953/

相关文章:

excel - VBA粘贴范围

vba - 将长日期重新格式化为与 Excel 中使用的语言不同的语言

javascript - 如何从类引用中实例化一个 javascript 对象?

javascript - 函数不断重复运行 Jquery

python - 用户定义的函数在Python中到底是如何运行的?

excel - 如果大于今天,则突出显示单元格

excel - 如何将 Excel 单元格的内容设置为等于字符串变量?

excel - VBA 用户窗体文本框默认值并突出显示

sql - Access - 检查月份和年份是否在日期范围内

vba - 我尝试在 VBA 中编写代码以将此公式插入单元格时一直失败