将用户定义的函数执行到另一个单元格VBA Excel中

时间:2014-08-18 09:13:32

标签: excel vba excel-vba

我需要自动化一个进程,该进程使用不同的输入参数执行各种(很多)用户定义的函数。

我正在使用I don't want my Excel Add-In to return an array (instead I need a UDF to change other cells)中找到的计时器API解决方案。

我的问题如下:"有人可以向我解释它是如何工作的吗?"如果我调试这段代码以理解和改变我需要的东西,我就会发疯。

1)假设我传递给公共函数AddTwoNumbers 14和45.在AddTwoNumber内部,Application.Caller和Application.Caller.Address被追加到一个集合中(好吧,比向量更容易,不是为了不打扰类型)。 Application.Caller是一种结构化对象,我可以在其中找到称为字符串的函数(在本例中为" my_function"),例如在Application.Caller.Formula中。 !在集合mCalculatedCells中我找不到存储的结果。

2)好的,公平的。现在我通过两个UDF例程,设置定时器,杀掉定时器。 只要我在AfterUDFRoutine2子中,mCalculatedCell(1)(我的集合中的第一个 - 也是唯一的 - 项目)在其文本字段中获得了精确的(??!?!?!!! ??)结果" 59"显然命令Set Cell = mCalculatedCells(1)(在左边我有一个范围,在右边我有......我不知道)能够把这个结果" 59&#34 ;进入变量Cell后,我可以用右侧单元格上的.Offset(0,1)Range属性写入。

我想理解这一点,因为我想在单个集合中提供更多任务,或者在要求新任务之前等待当前任务完成(否则我会覆盖59)与其他结果)。事实上,我在某处读到,使用API​​ setTimer安排的所有任务都将等待所有回调在执行之前执行(或类似的事情)。

你可以看到我不知所措。任何帮助都会非常受欢迎。

In the following I try to be more specific on what (as a whole) 
I am planning to achieved.

更具体地说,我有功能

public function my_function(input1 as string, Field2 as string) as double

/*some code */

end function

我有(让他们说)10个不同的字符串作为Field2。

我的策略如下:

1)I defined (with a xlw wrapper from a C++ code) the grid of all my input values

2)define as string all the functions "my_function" with the various inputs

3)use the nested API timer as in the link to write my functions IN THE RIGHT CELLS as FORMULAS (not string anymore)

3)use a macro to build the entire worksheet and then retrieve the results.

4)use my xlw wrapper xll to process further my data.

你可能想知道为什么我应该通过Excel而不是用C ++做所有事情。 (有时我问自己同样的事情......)我上面给出的原型my_function包含了一些我需要使用的Excel加载项,它们只能在Excel中使用。

它的工作情况非常好我只有1"实例" of_function为输入的给定网格写入。我甚至可以在同一个工作表中添加更多网格,然后使用API​​技巧为不同的网格编写各种不同的my_functions,然后对整个工作表进行完整的计算重建以获得结果。有用。 但是,只要我想在相同的API技巧中提供更多任务(因为对于相同的输入网格我需要更多调用my_function),我无法继续进行。

After Axel Richter's comment I would like to ad some other information

@Axel Richter 非常感谢你的回复。

很抱歉,几乎可以肯定我的目的并不清楚。

这里我尝试草拟一个例子,我使用整数来简化,让我们说my_function几乎与Excel的SUM函数一样工作(即使是Excel本机函数我可以直接将SUM调用到VBA但是这是为了一个例子。)

如果我有这些输入: input1 =" 14.5" 例如,Field2的不同值的向量(11; 0.52; 45139) 然后我想写一些my_function(它将两个值的总和作为输入)。

我必须在cell = my_function(14.5; 11)中写下,在另一个= my_function(14.5; 0.52)中,在第三个中写下= my_function(14.5; 45139)。

这些输入在我需要刷新数据时随时更改,然后我不能直接使用子(我认为),并且,无论如何,据我所知,在没有我链接的技巧的情况下直接写入,我将永远获得字符串:类似于&#39; = my_function(14.5; 0.52)。一旦评估(例如通过完全重建或翻过书面单元格并使F2 +返回),我将只给出字符串&#34; = my_function(14.5; 0.52)&#34;而不是它的结果。 我在开始时尝试使用一种Evaluate方法,一旦我写了像14.5 + 0.52这样的东西就能很好地工作,但是一旦使用了函数(也没有用户定义的函数)它就不会工作。< / p>

这是&#34;据我所知&#34;。在这种情况下,你可以启发我(也许可以显示一个更容易跟踪的轨道),它将会非常棒。

2 个答案:

答案 0 :(得分:0)

使用以下要求编辑:必须运行用户定义的工作表函数,因为此函数中调用了一些插件,并且这些插件仅在Excel工作表中起作用。该函数必须使用不同的参数运行多次,其结果必须从工作表中获取。

所以现在这是我的解决方案:

Public Function my_function(input1 As Double, input2 As Double) As Double
 my_function = input1 + input2
End Function

Private Function getMy_Function_Results(input1 As Double, input2() As Double) As Variant
 Dim results() As Double

 'set the Formulas
 With Worksheets(1)
  For i = LBound(input2) To UBound(input2)
   strFormula = "=my_function(" & Str(input1) & ", " & Str(input2(i)) & ")"
   .Cells(1, i + 1).Formula = strFormula
  Next

 'get the Results
  .Calculate
  For i = LBound(input2) To UBound(input2)
   ReDim Preserve results(i)
   results(i) = .Cells(1, i + 1).Value
  Next
 End With
 getMy_Function_Results = results
End Function

Sub test()
 Dim dFieldInput2() As Double
 Dim dInput1 As Double

 dInput1 = Val(InputBox("Value for input1"))

 dInput = 0
 iIter = 0
 Do
  dInput = InputBox("Values for fieldInput2; 0=END")
  If Val(dInput) <> 0 Then
   ReDim Preserve dFieldInput2(iIter)
   dFieldInput2(iIter) = Val(dInput)
   iIter = iIter + 1
  End If
 Loop While dInput <> 0

 On Error GoTo noFieldInput2
 i = UBound(dFieldInput2)
 On Error GoTo 0

 vResults = getMy_Function_Results(dInput1, dFieldInput2)

 For i = LBound(vResults) To UBound(vResults)
  MsgBox vResults(i)
 Next

noFieldInput2:
End Sub

用户可以先输入一个值input1,然后输入多个fieldInput2,直到输入值为0.然后计算并显示结果。

问候

阿克塞尔

答案 1 :(得分:0)

到目前为止,评论是正确的,因为它们重复了一个简单的观点,即称为工作表的用户定义函数只能返回一个值,并且禁止在工作表计算树的其他位置注入值的所有其他操作。

这不是故事的结局。你会注意到有一些插件,比如Reuters Eikon市场数据服务和Bloomberg for Excel,它们提供的功能存在于单个单元中,但是将数据块写入调用单元外的工作表

这些函数使用RTD(实时数据)API,该API在MSDN上记录:

How to create a RTD server for Excel

How to set up and use the RTD function in Excel

您可能会发现此链接也很有用:

Excel RTD Servers: Minimal C# Implementation

但是,RTD完全是关于Excel.exe之外的COM服务器,你必须用另一种语言(通常是C#或C ++)编写它们,这不是你问的问题:你想在VBA中这样做。 / p>

但我至少做了一个代表性的努力来给出'正确'的回答。

现在对于'错误'的回答,并且实际做微软的事情,你宁愿不做。您不能只调用函数,从函数调用子例程或方法,并使用子例程写入辅助目标:Excel将跟随链并检测到您正在将值注入到工作表计算中,并且写入将失败。

你必须在该链中插入一个中断;这意味着使用事件,或定时器调用,或(如在RTD中)外部过程。

我可以建议两种实际可行的方法:

1:监控Worksheet_Change事件中的单元格:

Private Sub Worksheet_Change(ByVal Target As Range)
Dim strFunc As String

strFunc = "NukeThePrimaryTargets"

If Left(Target.Formula, Len(strFunc) + 1) = strFunc Then
    Call NukeTheSecondaryTargets
End If

End Sub

...替代地

2:使用Timer回调API:

但是,我不会为此发布代码:它复杂,笨重,并且需要进行批次测试(因此我最终会在StackOverflow上发布未经测试的代码)。但它确实有效。

我可以举例说明VBA中经过测试的Timer回调:

Using the VBA InputBox for passwords and hiding the user's keyboard input with asterisks.

但这是一项不相关的任务。如果您愿意,请随意调整。