如何从VBA函数中填充Excel工作表中的单元格?

时间:2009-05-11 09:08:54

标签: arrays excel vba function formula

我只是想从VBA函数中填充电子表格中的单元格。举个例子,我想在一个单元格中键入= FillHere(),结果我会在一些单元格中填充一些数据。

我尝试过这样的功能:

Function FillHere()
  Dim rngCaller As Range
  Set rngCaller = Application.Caller
  rngCaller.Cells(1, 1) = "HELLO"
  rngCaller.Cells(1, 2) = "WORLD"
End Function

一旦我尝试修改范围,它就会中断。然后我尝试了这个(即使它不是我正在寻找的行为):

Function FillHere()
    Dim rngCaller As Range
    Cells(1, 1) = "HELLO"
    Cells(1, 2) = "WORLD"
End Function

这两个都不起作用。 但如果我使用F5从VBA启动此功能,它会起作用!在调用函数时似乎无法修改电子表格上的任何内容......虽然有些库会这样做...

我也试过(实际上这是我的第一个想法)从函数返回一个数组。问题是我只得到数组中的第一个元素(有一个技巧意味着在左上角选择一个带有公式的整个区域+ F2 + CTRL-SHIFT-ENTER,但这意味着用户需要知道通过提前数组的大小)。

我真的遇到了这个问题。我不是最终的最终用户所以我需要一些非常容易使用的东西,最好不要争论。

PS:对不起我已经问了这个问题,但当时我还没有注册,似乎我再也不能参与其他帖子了。

4 个答案:

答案 0 :(得分:3)

您需要分两步完成此操作:

将您的模块更改为:

Dim lastCall As Variant
Dim lastOutput() As Variant

Function FillHere()
    Dim outputArray() As Variant
    ReDim outputArray(1 To 1, 1 To 2)
    outputArray(1, 1) = "HELLO"
    outputArray(1, 2) = "WORLD"

    lastOutput = outputArray
    Set lastCall = Application.Caller

    FillHere = outputArray(1, 1)
End Function

Public Sub WriteBack()
    If IsEmpty(lastCall) Then Exit Sub
    If lastCall Is Nothing Then Exit Sub

    For i = 1 To UBound(lastOutput, 1)
        For j = 1 To UBound(lastOutput, 2)
            If (i <> 1 Or j <> 1) Then
                lastCall.Cells(i, j).Value = lastOutput(i, j)
            End If
        Next
    Next

    Set lastCall = Nothing
End Sub

然后,为了调用Sub进入VBA中的ThisWorkbook区域并添加如下内容:

Private Sub Workbook_SheetCalculate(ByVal Sh As Object)
    Call WriteBack
End Sub

这样做是返回topleft单元格的值,然后在计算完成后填充其余部分。我写这个的方式假定一次只调用一个FillHere函数。如果你想要同时重新计算多个,那么你需要一组更复杂的全局变量。

一句警告是,当它填充其他单元格时,它不会关心它覆盖的内容。

编辑: 如果要在XLA中在应用程序范围内执行此操作。 ThisWorkbook区域的代码应该类似于:

Private WithEvents App As Application

Private Sub App_SheetCalculate(ByVal Sh As Object)
    Call WriteBack
End Sub

Private Sub Workbook_Open()
    Set App = Application
End Sub

这将连接应用程序级别计算。

答案 1 :(得分:1)

您尝试做的事情将无法在Excel中运行 - 这是设计使然。

可以这样做,但是:

Function FillHere()
    Redim outputArray(1 To 1, 1 To 2)
    outputArray(1, 1) = "HELLO"
    outputArray(1, 2) = "WORLD"
    FillHere = outputArray
End Function

如果您随后在工作表中选择了两个相邻的单元格,请输入=FillHere()并按Control + Shift + Enter(以应用为数组公式),然后您应该看到所需的输出。

答案 2 :(得分:1)

从根本上说,函数只能影响从中调用的单元格。听起来您可能需要使用Worksheet_Change or Worksheet_SelectionChange events来触发预期范围内的单元格修改。

答案 3 :(得分:0)

您可以使用两阶段流程间接完成此操作: 编写UDF,以便以足够持久的方式存储数据(例如全局arrrays)。 然后有一个Addin,其中包含在每次计算事件后触发的应用程序事件,查看UDF存储的任何数据,然后重写必要的单元格(如果合适,还会显示有关覆盖的警告消息)并重置存储的数据。

这样,用户不需要在其工作簿中包含任何代码。

我认为(但不确定)这是彭博等人使用的技术。