Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vba UDF在任何地方都返回相同的值_Vba_Excel_With Statement_Udf - Fatal编程技术网

Vba UDF在任何地方都返回相同的值

Vba UDF在任何地方都返回相同的值,vba,excel,with-statement,udf,Vba,Excel,With Statement,Udf,我试图在vba中编写移动平均值代码,但下面的代码在任何地方都返回相同的值 Function trial1(a As Integer) As Variant Application.Volatile Dim rng As Range Set rng = Range(Cells(ActiveCell.Row, 2), Cells(ActiveCell.Row - a + 1, 2)) trial1 = (Application.Sum(rng)) * (1 / a)

我试图在vba中编写移动平均值代码,但下面的代码在任何地方都返回相同的值

Function trial1(a As Integer) As Variant
    Application.Volatile
    Dim rng As Range
    Set rng = Range(Cells(ActiveCell.Row, 2), Cells(ActiveCell.Row - a + 1, 2))
    trial1 = (Application.Sum(rng)) * (1 / a)
End Function
不属于UDF,因为它会更改。有时,它甚至不在同一工作表上

如果需要引用工作表中自定义UDF函数所在的单元格,请使用以下方法。可以使用来明确标识工作表(并避免进一步混淆)

您已应用ª方法,但未明确指定父工作表,因此允许将范围平均为默认值

通过返回a的结果和一些数学计算平均值。工作表的一个命令可能会返回相同的结果,但空白单元格的处理方式会有所不同

        trial1 = Application.Average(rng)


当整个工作簿中的任何内容发生更改时,而不仅仅是当影响其结果的内容发生更改时,Volatile函数都会重新计算。

我认为Application.ActiveCell不是您应该在这里使用的。 假设“a”是子集的大小,并且数据集是右侧的1列,则Application.ThisCell更合适。 此外,我将简单地使用“WorksheetFunction.Average”而不是“Application.Sum”,并添加“Application.Volatile”,以便在工作表上发生更新时重新计算平均值

因此,解决您的问题的一个方法是:

Public Function Trial1(a As Integer) As Variant
  Application.Volatile
  Trial1 = WorksheetFunction.Average(Application.ThisCell(1, 2).Resize(a))
End Function
这里的另一个解决方案是使用Control/Shift/Enter输入的数组公式:

Public Function MovAvg(dataset As Range, subsetSize As Integer)
  Dim result(), subset As Range, i As Long
  ReDim result(1 To dataset.Rows.count, 1 To 1)
  Set subset = dataset.Resize(subsetSize)

  For i = 1 To dataset.Rows.count
    result(i, 1) = WorksheetFunction.Average(subset.offset(i - 1))
  Next

  MovAvg = result
End Function
要使用此数组函数,请执行以下操作:

  • 选择将写入所有结果的范围(应为数据集的大小)
  • 类型“=MovAvg(A1:A100,2)”,其中A1:A100是数据源,2是子集的大小
  • 按Ctrl+Shift+Enter键

    • 对于一个给定数字的UDF来说,计算移动平均值对我来说有点奇怪。如果要在工作表中使用此自定义项,我相信您会将其放在现有数据的旁边,如果您想更改平均金额范围的大小,您可以手动更新它们吗

      假设您可以指定一个范围“<强>移动平均值> /强>”来存储计算平均值的范围的大小,以及现有数据的右边的平均量,请考虑如下:

      • 范围C2命名为
        MovingAverageSize
      • 从B3和B3以下存储的数据
      • 移动平均结果存储在数据右侧的一列中
      • 如果数据小于MovingAverageSize,则SUM函数会相应调整
      • 发生任何计算错误,结果为零
      • 每次MovingAverageSize更改值时,它都会触发一个子系统来更新公式(代码放在工作表对象中,而不是普通模块中)
      • 或者,您可以更改代码,将MovingAverage放在MovingAverageSize的同一列中,这样您就可以在彼此旁边比较一些不同的大小
      工作表对象中的代码:

      Option Explicit
      
      Private Sub Worksheet_Change(ByVal Target As Range)
          If Target.Count = 1 Then
              If Target.Address = ThisWorkbook.Names("MovingAverageSize").RefersToRange.Address Then UpdateMovingAverage Target
          End If
      End Sub
      
      Private Sub UpdateMovingAverage(ByRef Target As Range)
          Dim oRngData As Range, oRng As Range, lSize As Long, lStartRow As Long
          Debug.Print "UpdateMovingAverage(" & Target.Address & ")"
          If IsNumeric(Target) Then
              lSize = CLng(Target.Value)
              If lSize <= 0 Then
                  MsgBox "Moving Average Window Size cannot be zero or less!", vbExclamation + vbOKOnly
              Else
                  ' Top Data range is "B3"
                  Set oRngData = Target.Parent.Cells(3, "B") ' <-- Change to match your top data cell
                  lStartRow = oRngData.Row
                  ' Set the Range to last row on the same column
                  Set oRngData = Range(oRngData, Cells(Rows.Count, oRngData.Column).End(xlUp))
                  Application.EnableEvents = False
                  For Each oRng In oRngData
                      If (oRng.Row - lSize) < lStartRow Then
                          oRng.Offset(0, 1).FormulaR1C1 = "=iferror(sum(R[" & lStartRow - oRng.Row & "]C[-1]:RC[-1])/MovingAverageSize,0)"
                      Else
                          oRng.Offset(0, 1).FormulaR1C1 = "=iferror(sum(R[" & 1 - lSize & "]C[-1]:RC[-1])/MovingAverageSize,0)"
                      End If
                  Next
                  Application.EnableEvents = True
                  Set oRngData = Nothing
              End If
          End If
      End Sub
      
      选项显式
      私有子工作表_更改(ByVal目标作为范围)
      如果Target.Count=1,则
      如果Target.Address=thiswook.Names(“MovingAverageSize”).referestorange.Address,则UpdateMovingAverage目标
      如果结束
      端接头
      私有子UpdateMovingAverage(ByRef目标作为范围)
      变暗或变宽为范围,或变宽为范围,变大为长,变小为长
      Debug.Print“UpdateMovingAverage(&Target.Address&')”
      如果是数字(目标),则
      lSize=CLng(目标值)
      
      如果lSizeUDF仅应在作为参数传递时访问范围。 此外,您应该消除Application.Volatile,因为(1)您的计算是确定性的,而不是易变的,(2)每当输入范围中的任何单元格发生变化时,Excel将自动重新计算您的UDF,(3)因为UDF中的“Volatile”属性会使模型非常慢,因此在不必要时应避免使用它。 因此,对于移动平均线,正确的公式是:

      Public Function SpecialMovingAverage(Rng as Excel.Range) As Double
          Dim denominator as Integer
          denominator = Rng.Cells.Count
          if Denominator = 0 then SpecialMovingAverage = 0: exit function 
          ' write your special moving average logic below
          SpecialMovingAverage = WorksheetFunction.Average(Rng) 
      End Function
      
      注:我在两条评论后更改了答案,因为我最初没有看到问题是在移动平均线之后(可能是在我的答案之后更改了问题,或者我最初没有达到UDF规定的目标)。

      我相信

    • trial1()函数位于一个或多个单元格中,作为公式的一部分或单独存在

    • 您希望在用户更改工作表上的任何单元格时重新计算这些单元格

    • 为此,您需要识别发生更改的单元格。此单元格不是由

      A.ActiveCell-因为计算开始时光标所在的单元格;它可能在任何地方,但不在被改变的细胞上

      B.Application.ThisCell-因为它返回调用用户定义函数的单元格,而不是已更改的单元格

      发生更改的单元格将传递给工作表的更改事件。该事件由一个Range类型的参数触发,即已更改的范围。您可以使用该参数来标识已更改的单元格,并将其传递给trial1(),可能是通过一个全局变量(是的,我知道)


      我在工作表中尝试了这一点,效果很好,所以请告诉我您的结果。

      那么这里的问题是什么?我的代码似乎不起作用。它为所有单元格返回相同的值。如果我删除application.volatile行,我必须手动按F2键并输入每个单元格以获得正确答案。我认为原因是函数无法识别动态范围中存在的变化,但不知道如何修复它。我测试了它,但它没有在任何地方返回相同的值,它似乎做了它应该做的事情。您的问题的问题是,我们不确切知道您想要什么,我们应该参考您的代码来了解您正在做什么。但是你的代码可能是错的。从我看来:1。选择一个单元格,触发调用函数Tria的宏
      Public Function SpecialMovingAverage(Rng as Excel.Range) As Double
          Dim denominator as Integer
          denominator = Rng.Cells.Count
          if Denominator = 0 then SpecialMovingAverage = 0: exit function 
          ' write your special moving average logic below
          SpecialMovingAverage = WorksheetFunction.Average(Rng) 
      End Function