我需要自动化一个进程,该进程使用不同的输入参数执行各种(很多)用户定义的函数。
我正在使用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;。在这种情况下,你可以启发我(也许可以显示一个更容易跟踪的轨道),它将会非常棒。
答案 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中)外部过程。
我可以建议两种实际可行的方法:
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
...替代地
但是,我不会为此发布代码:它复杂,笨重,并且需要进行批次测试(因此我最终会在StackOverflow上发布未经测试的代码)。但它确实有效。
我可以举例说明VBA中经过测试的Timer回调:
Using the VBA InputBox for passwords and hiding the user's keyboard input with asterisks.
但这是一项不相关的任务。如果您愿意,请随意调整。