【问题标题】:Cannot VBA write data to cells in Excel 2007/2010 within a functionVBA 无法在函数内将数据写入 Excel 2007/2010 中的单元格
【发布时间】:2012-02-28 04:15:18
【问题描述】:

我想通过 VBA 为单元格设置值。我用谷歌搜索过,看到了一些解决方案:

Sheets("SheetName").Range("A1").value = someValue
Sheets("SheetName").Cells(1,1).value = someValue

使用这种代码,我只能从单元格 A1 中读取数据,但无法为其设置新值。

更新

设置单元格 A1 值的代码放在 Function 中,如下所示。

Function abb()
    Sheets("SheetName").Range("A1").value = 122333
    abb = 'any thing'
End Function

在单元格 B2 中,我设置了 =abb() 并按 Enter。我得到了#VALUE,但在 A1 没有任何反应。

将此代码放入宏中,它可以工作。

我的问题是,如何让 A1 在函数中具有值?

【问题讨论】:

  • 你有两个选择。要么将其作为子例程运行,要么使用 stackoverflow.com/q/8520732/641067 中的 UDF 计时器解决方法。前者更容易。
  • 如果你想让一个函数在A1中返回一些东西,那么函数调用应该在A1中输入。这就是 Excel 的工作方式。
  • 为什么不使用工作表更改事件捕获对 B2 的更改,然后填充 A1?从您的代码中,该函数将不会更新,因为它没有任何参数。

标签: excel excel-2007 excel-2010 vba


【解决方案1】:

根据您上面的评论,您想尝试这种方法

如果输入
=abb()
进入任何单元格

然后该表的单元格 A1 将设置为 12333

这是要更新的行以选择要更新的单元格并在其中放置一个值
Range("A1").Value = 122333

来自I don't want my Excel Add-In to return an array (instead I need a UDF to change other cells)

我正在从Kevin Jones aka Zorvek 转发这个魔法,因为它位于behind the EE Paywall(如果有人可以访问,请附上链接)

虽然 Excel 严格禁止 UDF 更改任何单元格、工作表、 或工作簿属性,有一种方法可以在 使用 Windows 计时器和 Application.OnTime 计时器调用 UDF 顺序。必须在 UDF 中使用 Windows 计时器,因为 Excel 忽略 UDF 内的任何 Application.OnTime 调用。但是因为 Windows 计时器有限制(Excel 将立即退出,如果 如果正在编辑单元格,Windows 计时器会尝试运行 VBA 代码或 对话框打开),它仅用于调度 Application.OnTime 计时器,一个安全计时器,Excel 仅允许在单元格被触发时触发 未被编辑,也没有打开任何对话框。

下面的示例代码说明了如何从 在 UDF 中,如何使用该计时器例程来启动 Application.OnTime 计时器,以及如何将仅已知的信息传递给 UDF 到后续定时器执行的例程。下面的代码必须是 放置在常规模块中。

Declare Function SetTimer Lib "user32" ( _
      ByVal HWnd As Long, _
      ByVal nIDEvent As Long, _
      ByVal uElapse As Long, _
      ByVal lpTimerFunc As Long _
   ) As Long

Private Declare Function KillTimer Lib "user32" ( _
      ByVal HWnd As Long, _
      ByVal nIDEvent As Long _
   ) As Long

Private mCalculatedCells As Collection
Private mWindowsTimerID As Long
Private mApplicationTimerTime As Date

Public Function abb()

' This is a UDF that returns the sum of two numbers and starts a windows timer
' that starts a second Appliction.OnTime timer that performs activities not
' allowed in a UDF. Do not make this UDF volatile, pass any volatile functions
' to it, or pass any cells containing volatile formulas/functions or
' uncontrolled looping will start.

   abb = "Whatever you want"

   ' Cache the caller's reference so it can be dealt with in a non-UDF routine
   If mCalculatedCells Is Nothing Then Set mCalculatedCells = New Collection
   On Error Resume Next
   mCalculatedCells.Add Application.Caller, Application.Caller.Address
   On Error GoTo 0

   ' Setting/resetting the timer should be the last action taken in the UDF
   If mWindowsTimerID <> 0 Then KillTimer 0&, mWindowsTimerID
   mWindowsTimerID = SetTimer(0&, 0&, 1, AddressOf AfterUDFRoutine1)

End Function

Public Sub AfterUDFRoutine1()

' This is the first of two timer routines. This one is called by the Windows
' timer. Since a Windows timer cannot run code if a cell is being edited or a
' dialog is open this routine schedules a second safe timer using
' Application.OnTime which is ignored in a UDF.

   ' Stop the Windows timer
   On Error Resume Next
   KillTimer 0&, mWindowsTimerID
   On Error GoTo 0
   mWindowsTimerID = 0

   ' Cancel any previous OnTime timers
   If mApplicationTimerTime <> 0 Then
      On Error Resume Next
      Application.OnTime mApplicationTimerTime, "AfterUDFRoutine2", , False
      On Error GoTo 0
   End If

   ' Schedule timer
   mApplicationTimerTime = Now
   Application.OnTime mApplicationTimerTime, "AfterUDFRoutine2"

End Sub

Public Sub AfterUDFRoutine2()

' This is the second of two timer routines. Because this timer routine is
' triggered by Application.OnTime it is safe, i.e., Excel will not allow the
' timer to fire unless the environment is safe (no open model dialogs or cell
' being edited).

   Dim Cell As Range

   ' Do tasks not allowed in a UDF...
   Application.ScreenUpdating = False
   Application.Calculation = xlCalculationManual
   Do While mCalculatedCells.Count > 0
      Set Cell = mCalculatedCells(1)
      mCalculatedCells.Remove 1
      Range("A1").Value = 122333
   Loop
   Application.Calculation = xlCalculationAutomatic
   Application.ScreenUpdating = True
   End Sub

【讨论】:

  • @Jean-FrançoisCorbett 我同意。我很惊讶有人能够想到然后执行此操作。虽然它确实显示出“做不到”的危险。
  • 我的天哪 +1 但我宁愿遵守你不能这样做的规则
【解决方案2】:

您不能使用 B2 中的函数更改单元格 A1。

访问:Description of limitations of custom functions in Excel 。正文包括:

“由工作表单元格中的公式调用的用户定义函数不能改变Microsoft Excel的环境。这意味着这样的函数不能执行以下任何操作:

  • 在电子表格中插入、删除或格式化单元格。
  • 更改另一个单元格的值。 [我的突出显示]
  • 向工作簿移动、重命名、删除或添加工作表。
  • 更改任何环境选项,例如计算模式或屏幕视图。
  • 为工作簿添加名称。
  • 设置属性或执行大多数方法。"

为什么要以这种方式更改单元格 A1?说明您的目标,也许有人可以提供帮助。

【讨论】:

  • 其实可以做,但是比较复杂。见stackoverflow.com/q/8520732/641067
  • @brettdj。我错过了这个问题和你的回答,这很有趣。但是,这不是我想推荐给新手的技术。我认为这是提问者告诉我们他认为他的问题可以如何解决而不是他的问题是什么的情况。我想知道他为什么要B2中的一个函数来改变A1?
  • @TonyDallimore 我想要缓存值。假设我计算了很多单元格Range(B1:B1000) 的总和,我想将此总和值缓存到 A1(或任何单元格),所以我重新打开 excel 文件,excel 不需要重新计算
  • @brettdj 我已阅读 (stackoverflow.com/q/8520732/641067) ,但我不知道如何使用参数调用 AfterUDFRoutine2
  • @Davuz。您希望缓存复杂计算的结果,以免重复计算。您将需要一些系统(1)知道需要复杂的计算,(2)执行它并保存结果,(3)阻止它再次发生。您还需要这个系统比 Excel 的控制重新计算的系统更好。您是否尝试过重新计算时间?您想节省多少时间以及频率如何?
【解决方案3】:

如果您想用一个公式修改两个单元格,您可能需要考虑从函数中返回一个数组。这是一个例子:

Function abb()
    Dim arr As Variant
    ReDim arr(1 To 2)
    arr(1) = "aardvark"
    arr(2) = "bee"
    abb = arr
End Function

选择单元格 A2 到 B2。键入 =abb() 并按 ShiftCtrlEnter 以指定它是一个数组公式。然后,此公式同时修改两个单元格(A2 和 B2)。

也许你可以自定义它来做你想做的事。

【讨论】:

    【解决方案4】:

    它应该工作 - 试试这个

    1. 打开一个新的 Excel 工作表
    2. 创建一个新宏
    3. 添加此Sheets("Sheet1").Range("A1").Value2 = "value"

    .Value.Value2 都可以使用,请确保工作表名称正确。

    【讨论】:

    • 当我调试时,我在语句“Sheets("Sheet1").Range("A1").Value2 = "处停止。不知道为什么?
    • 工作表的名称是什么,如果不是Sheet1,那么问题就会出现.. 试试这个Sheets(1).Range("A1").Value,索引将有助于找到正确的工作表,一旦这对你有用可以用实际工作表名称替换索引。
    • @Davuz:“停止”是什么意思?它会抛出任何错误吗?工作簿是否以只读方式打开?
    • @shahkalpesh 当我调试时,它运行到该语句并抛出异常(也许......)并在 excel 输出“#VALUE”
    • @AnanthaSharma 是的,它适用于宏。但不适用于功能。我已经更新了我上面的问题。请帮忙
    猜你喜欢
    • 2010-12-06
    • 2015-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-18
    • 1970-01-01
    相关资源
    最近更新 更多