简体   繁体   English

从vba中的sub调用函数

[英]Call a function from sub in vba

I wrote this function, which is supposed to take the user defined cell from a chosen range and add or multiply its value by an user defined number. 我编写了此函数,该函数应该从选定的范围内获取用户定义的单元格,并将其值与用户定义的数字相加或相乘。 The output should be an array with one changed cell. 输出应为具有一个已更改单元格的数组。

I was able to compile it; 我能够编译它; however, I cannot call it. 但是,我不能这样称呼。

I tried to replicate what this and this but it failed. 我试图复制这个这个,但是失败了。

Function Macro1(cellref As Range, row_number As Long, column_number As Long, x As Double, method As Integer) As Variant
'Number, which will be added or multiplied by chosen cell value in an array
'One for multiplication, two for addition
  If method = 1 Then
    Cells(row_number, column_number) = Cells(row_number, column_number) * x
  ElseIf method = 2 Then 
    Cells(row_number, column_number) = Cells(row_number, column_number) + x
  End If
  Result = Macro1
End Function

Sub try()
  Macro1(Range("A1:AX3").Select, 2, 2, 0.5, 1) = Result
End Sub

When running this code, I get the error message "Run-time error 424, object required". 运行此代码时,出现错误消息“运行时错误424,所需对象”。 The line Macro1(Range("A1:AX3").Select, 2, 2, 0.5, 1) = Result gets red highlighted Macro1(Range("A1:AX3").Select, 2, 2, 0.5, 1) = Result突出显示为红色

Then I tried 然后我尝试

Function Macro1(cellref As Range, row_number As Long, column_number As Long, x As Double, method As Integer) As Variant
'Number, which will be added or multiplied by chosen cell value in an array
'One for multiplication, two for addition
  If method = 1 Then
    Cells(row_number, column_number) = Cells(row_number, column_number) * x
  ElseIf method = 2 Then 
    Cells(row_number, column_number) = Cells(row_number, column_number) + x
  End If
  Result = Macro1
End Function

Sub try()
  Macro1(Worksheets("Macro1").Range("A1:AX3"), 2, 2, 0.5, 1)
End Sub

But I got "Type mismatch Error 13" message. 但是我收到“类型不匹配错误13”消息。 The line Sub try() is highlighted in yellow and the line below it is red Sub try()行以黄色突出显示,其下面的行为红色

I see several issues: 我看到几个问题:

First , the line ,行

Result = Macro1

In Macro1 is a recursive call to Macro1 . Macro1是对Macro1的递归调用。 ie Macro1 is trying to call itself. Macro1正在尝试自我调用。

You'll get an error because Macro1 requires parameters, the first of which is an Object (a Range is an Object ), and you're not supplying an object parameter. 因为Macro1需要参数(第一个参数是ObjectRangeObject )),并且没有提供对象参数,所以会出现错误。 As a matter of fact, you're not supplying any required parameters in this call. 实际上,您没有在此调用中提供任何必需的参数。


Second , the code: ,代码:

<functionName> = value

Is backwards. 是倒退。 That line is attempting to set Macro1 (the <functionName> on the left-hand side of the assignment operator = ) to the value of Result . 该行尝试将Macro1 (赋值运算符=左侧的<functionName> )设置为Result的值。 This isn't possible (at least not in in VBA). 这是不可能的(至少在VBA中没有)。 I believe that what you want is: 我相信您想要的是:

result = Macro1(Worksheets("Macro1").Range("A1:AX3"), 2, 2, 0.5, 1)

Which will execute Macro1 with the specified parameters, then assign the returned value (a Variant as you've defined it) to the Variant variable (because you haven't Dim med it) result . 将执行Macro1使用指定的参数,然后将返回的值( Variant如你定义它)的Variant变量(因为你没有Dim配有它) result


Third , you've declared Macro1 to be a Function , but there's no need to - it's not returning a value, it's setting cells in the Range it's been passed. 第三 ,您已经将Macro1声明为Function ,但是没有必要-它返回值,而是将其设置为已传递的Range的单元格。 You'd be best served by changing this to a Sub , since that's the kind of work it's doing. 最好将其更改为Sub ,因为这是它正在做的工作。 I think you may have been intending to have it return a value with the line Result = Macro1 , but as mentioned, that ain't gonna do it. 我认为您可能已经打算让它在Result = Macro1行中返回一个值,但是如上所述,它不会这样做。 VBA works by assigning the value to be returned to the Function name, not with a return function as some other languages do. VBA通过将要返回的值分配给Function名称来工作,而不是像某些其他语言那样使用return函数。 If you do have some sort of result you want to return, you'd assign it with the code: 如果确实有想要返回的某种结果,则可以使用以下代码为其分配:

Macro1 = <the value to be returned>

However, I'm not sure what you'd actually be returning from this as a Function because it can work on a Range not an individual Cell 但是,我不确定您从Function实际返回的内容是什么,因为它可以在一个Range而不是单个Cell


Fourth , I'm not entirely certain why you're accepting a whole Range as the parameter to Macro1 , then specifying a single Cell within it. 第四 ,我不确定您为什么要接受整个Range作为Macro1的参数,然后在其中指定单个Cell Passing in ...Range("A1:AX3") , then specifying I want column 2 and Row 2 of that range is way too much cognitive effort to sort out what cell you're after. 传递...Range("A1:AX3")然后指定我想column 2Row 2的那个范围是太多的认知努力挑选出你是什么细胞后。 Why not just pass in ...Range("B2") and be done with it? 为什么不仅仅传递...Range("B2")并完成它呢? The benefits are 好处是

1) Macro1 works directly with the desired cell and the desired cell only 1) Macro1直接与所需的单元格一起使用,并且仅与所需的单元格一起使用

2) The caller specifies the desired cell and the desired cell only 2)呼叫者仅指定所需的单元格和所需的单元格

3) You eliminate otherwise unnecessary parameters from the param list. 3)从参数列表中消除其他不必要的参数。


Fifth your Macro1 receives a Range parameter to work on, but never references it. 第五,您的Macro1收到一个Range参数以供处理,但从未引用它。 You accept cellref As Range , but in the code body, you're working with Cells() and never once reference cellref . 您接受cellref As Range ,但是在代码体中,您正在使用Cells()并且从未引用过cellref There are a couple of issues with this: 有两个问题:

1) You have an unspecified Cells() which will automatically reference the ActiveSheet , whether that's your intent or not. 1)您有一个未指定的Cells() ,它将自动引用ActiveSheet ,无论您的意图与否。

2) You're not at all working with whatever it is that you're passing in when you call Macro1 (which could be on any Worksheet in the Workbook ). 2)您根本不使用调用Macro1时传递的内容(它可以在Worksheet Workbook 任何 Worksheet上)。

You have done a great job of being very specific in your call to Macro1 by specifying Worksheets("Macro1").Range("A1:AX3") so that VBA knows exactly what cell you're after. 通过指定Worksheets("Macro1").Range("A1:AX3")以便VBA 确切知道要在哪个单元格上,您在 Macro1的调用中非常具体。 However, if you happen to be looking at Sheet2 at the time of the call, Macro1 will be working with Worksheets("Sheet2").Range("B2") because at this point Activesheet = Worksheets("Sheet2") instead of Worksheets("Macro1") . 但是,如果您恰巧在调用时正在查看Sheet2 ,则Macro1将与Worksheets("Sheet2").Range("B2")因为此时Activesheet = Worksheets("Sheet2")而不是Worksheets("Macro1")


Sixth you're doing no sanity checking on your input values. 第六,您不对输入值做任何检查。 What happens if the value in the passed cell happens to be red instead of 17.256 . 如果传递的单元格中的值恰好是red而不是17.256会发生什么。 What's the value of red * 2 ? red * 2的值是多少? Why, it's a Runtime error #13. Type mismatch 为什么,这是Runtime error #13. Type mismatch Runtime error #13. Type mismatch . Runtime error #13. Type mismatch You need some sort of sanity checking or error handling to ensure you're working with numeric data. 您需要某种形式的健全性检查或错误处理,以确保您使用的是数字数据。


In the end, I would suggest something like this with a pre-execution sanity check: 最后,我将通过执行前的健全性检查来建议这样的事情:

Function Macro1(cellref As Range, x As Double, method As Long) As Variant
'Number, which will be added or multiplied by chosen cell value in an array
'One for multiplication, two for addition

  Dim Result As Double

  If Not IsNumeric(cellref.Value) Then
    MsgBox ("The cell does not contain a numeric value")
    Exit Function
  End If

  If method = 1 Then
    Result = cellref.Value * x
  ElseIf method = 2 Then
    Result = cellref.Value + x
  End If
  Macro1 = Result

End Function

Sub try()
  With Worksheets("Sheet1")
    .Range("B2") = Macro1(.Range("B2"), 0.5, 1)
  End With
End Sub

Alternatively, you could go with error handling and do it like this: 或者,您可以进行错误处理并按以下方式进行操作:

Option Explicit

Function Macro1(cellref As Range, x As Double, method As Long) As Variant
'Number, which will be added or multiplied by chosen cell value in an array
'One for multiplication, two for addition

  On Error GoTo ErrorHandler

  Dim Result As Double

  If method = 1 Then
    Result = cellref.Value * x
  ElseIf method = 2 Then
    Result = cellref.Value + x
  End If

CleanExit:
  Macro1 = Result

ErrorHandler:
  MsgBox ("The cell does not contain a numeric value")
  Result = vbNull
  Resume CleanExit

End Function

Sub try()
  With Worksheets("Sheet1")
    .Range("B2") = Macro1(.Range("B2"), 0.5, 1)
  End With
End Sub

Notice the inclusion of Option Explicit that requires that you declare ( Dim ) all variables before you use them. 请注意, Option Explicit的包含要求您在使用它们之前声明所有变量( Dim )。 This will help eliminate other potential errors where you misspell Variable1 as Varaible1 and VBA "helpfully" creates a whole new variable for you creating a very difficult bug to find. 这将有助于消除其他可能的错误,因为您会错误地将Variable1拼写为Varaible1而VBA“有帮助”地为您创建了一个全新的变量,从而创建了一个很难发现的错误。


Based on some of the other comments, I think that you are attempting to call this for many cells in a range. 根据其他一些评论,我认为您正在尝试为范围内的许多单元格调用此方法。 If that's the case, you can add some simple looping to the Try() procedure to run through all the cells that this needs to be applied to. 在这种情况下,您可以向Try()过程添加一些简单的循环,以遍历所有需要应用的单元格。 If not, and you're somehow trying to apply this to one cell in a Range based on other values in that range, you'll need to modify some portion of it to do what you're after. 如果不是,并且您正试图基于该范围内的其他值将其应用于“ Range的一个单元格,则需要修改它的某些部分以执行后续操作。 I hope there's enough info in this post for you to figure out how to do that. 我希望这篇文章中有足够的信息供您了解如何做到这一点。 If not, that would probably make for a great follow up question once you've fully grokked what's going on in changing this one cell. 如果没有,那么一旦您完全理解了更改此单元格的过程后,可能会提出一个很大的后续问题。


As a side note, there is a great OSS VBE add-on called Rubberduck which will help you find and fix a lot of these types of errors. 附带说明一下,有一个很棒的OSS VBE附加软件,名为Rubberduck ,可帮助您发现和修复许多此类错误。 I'm a great fan of the tool, I use it daily, and I've contributed to the project as well. 我是该工具的忠实拥护者,每天都会使用它,我也为该项目做出了贡献。

First, you don't need the cellref parameter you aren't using it. 首先,不需要不需要的cellref参数。

as @nacorid and @Jnevill said result = Macro1 doesn't do anything, the code just skips it. 就像@nacorid和@Jnevill所说的那样,结果= Macro1不执行任何操作,代码只是跳过了它。 If you want a return on your function it would be Macro1 = result. 如果要返回函数,则为Macro1 = result。 However, you don't assign anything to result so it still won't do anything. 但是,您不分配任何结果,因此它仍然不会做任何事情。 You would also need to create an assignment in sub try() to capture the return. 您还需要在sub try()创建一个分配以捕获返回值。

I am not sure what you mean by your expected output is an array with one changed cell, You are changing a cell but it isn't an array you are just directly changing the value of it with this line: Cells(row_number, column_number) = Cells(row_number, column_number) * x 我不确定您期望的输出是一个具有一个已更改单元格的数组,您正在更改一个单元格,但它不是一个数组,您只是在此行直接更改其值: Cells(row_number, column_number) = Cells(row_number, column_number) * x

Edit: Here is how you load up an array, modify and paste it somewhere else. 编辑:这是您加载阵列,修改并将其粘贴到其他位置的方式。

You will need to add some error handling to not get type mismatches. 您将需要添加一些错误处理,以免类型不匹配。

You may also want to make it a little more dynamic with an offset number for the pasterange. 您可能还希望使用pasterange的偏移量使其更具动态性。

sub macro1()
    Dim rngarr() As Variant
    Dim divisor As Double
    Dim targetcol As Long
    Dim targetrow As Long
    Dim pasterange As Range

    rngarr = Range("A1:AX3").Value
    'Remember that your array starts at index 1
    'A range that starts at row 2 will still have an index 1
    targetcol = 2
    targetrow = 2

    divisor = 0.5

    rngarr(targetrow, targetcol) = rngarr(targetrow, targetcol) * divisor

    Set pasterange = Range("A5:AX7")

    pasterange = rngarr
end sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM