数据更改时图表不会自动更新

时间:2010-12-16 22:50:47

标签: excel excel-vba excel-2007 vba

希望这很简单。我在MS Excel中有一系列图表指向同一工作表上的数据。工作表上的数据使用VBA函数计算。当VBA函数更新数据时,新数字不会反映在指向它们的图表中。我试过调用Application.Calculate,但是没有做到这一点。有什么想法吗?


UDPATE:

我能够以更小的规模复制这个问题。方法如下:

  • 创建新工作簿
  • 将工作表1重命名为“摘要”
  • 将工作表2重命名为“数据”
  • 在VBA编辑器中打开摘要表并粘贴以下代码:

    Private Sub Worksheet_Change(ByVal Target As Range)
       If Target.Parent.Range("worksheetDate") = Target Then
          Application.CalculateFull
       End If
    End Sub
    
  • 创建新的VBA模块

  • 将以下代码粘贴到新的VBA模块中(道歉 - 我不能让Stack Overflow在我的生活中正确地格式化 - 这是我能做的最好的事情):

     Function getWeekValue (weekNumber As Integer, valuesRange As Range) As Integer   
    
     Dim aCell As Range  
     Dim currentDate As Date  
     Dim arrayIndex As Integer  
     Dim weekValues(1 To 6) As Integer  
    
     currentDate = ThisWorkbook.Names("worksheetDate").RefersToRange.Value
     arrayIndex = 1  
     For Each aCell In valuesRange 
         If month(currentDate) = month(ThisWorkbook.Sheets("Data").Cells( _  
                                       aCell.Row - 1, aCell.Column)) Then
             weekValues(arrayIndex) = aCell.Value 
             arrayIndex = arrayIndex + 1 
         End If 
     Next
    
     getWeekValue = weekValues(weekNumber)   
     End Function  
    

  • 修改数据工作表以匹配以下图像:

alt text

  • 选择单元格B1并将范围命名为“worksheetDate”
  • 在下图中复制第1行到第3行:

alt text

  • 在第4行的“第X周”标题下,输入以下公式

 = getWeekValue(1, Data!$A$2:$M$2)

每周将getWeekValue函数的第一个参数递增1(例如,第1周传递1,第2周传递2,第3周传递3,等等。

  • 使用单元格A3到E4创建条形图作为数据
  • 将单元格B2中的日期更改为10/1/2010和12/31/2010之间的日期,选择当前位于单元格中的月份以外的月份。例如,如果日期为12/11/2010,请将其更改为11/11/2010或10/11/2010。请注意,数据和图表都会正确更新。
  • 修改单元格B2增益中的日期。请注意,数据会更新,但图表不会更新。

奇怪的是,经过一段时间(几分钟)后,图表终于更新了。我不确定这是否是因为我一直在执行其他触发更新的活动,或者因为Excel在几分钟后触发更新。

9 个答案:

答案 0 :(得分:1)

在我的更改结束时,我关闭工作簿并重新打开它。这似乎是为我更新所有内容的最简单,最可靠的方式。

答案 1 :(得分:1)

刚刚想出了解决这个问题的方法,因为我也遭遇了同样的问题。

我刚刚添加了#34; DoEvents()"在打印或导出之前,图表已刷新。

例如

Sub a()
   Dim w As Worksheet
   Dim a
   Set w = Worksheets(1)

   For Each a In w.Range("a1:a5")
     a.Value = a.Value + 1
   Next

   DoEvents

End Sub  

答案 2 :(得分:0)

例如:

Sub a()
   Dim w As Worksheet
   Dim a
   Set w = Worksheets(1)

   For Each a In w.Range("a1:a5")
     a.Value = a.Value + 1
   Next

   w.ChartObjects(1).Chart.Refresh

End Sub  

alt text

答案 3 :(得分:0)

这个解决方案对我有用。对于违规工作表,请添加:

Private Sub Worksheet_Activate()
  Dim rngSelection          As Range
  Dim objChartObject        As ChartObject
  Dim objChart              As Chart
  Dim objSeriesCollection   As SeriesCollection
  Dim objSeries             As Series
  Dim strFormula            As String

  Set rngSelection = Selection

  For Each objChartObject In Me.ChartObjects
    Set objChart = objChartObject.Chart
    Set objSeriesCollection = objChart.SeriesCollection
    For Each objSeries In objSeriesCollection
      strFormula = objSeries.Formula

      objSeries.Delete

      Set objSeries = objSeriesCollection.NewSeries

      objSeries.Formula = strFormula
    Next objSeries
  Next objChartObject

  rngSelection.Select
End Sub

答案 4 :(得分:0)

问题可能是getWeekValue的参数列表,其中只包含周数和数据流。

如果你添加第三个参数,workheetDate,那么Excel的重新计算引擎将被击中头部,因为getWeekValue使用了worksheetDate中保存的值。在您当前的实现中,这个事实仅存在于VBA代码中,重新计算引擎可能看不到它。

我这样对冲是因为我不了解重新计算引擎的内部工作原理。 (也许有人比我对我的猜测更能了解这一点)但我确实做了一个测试,其中getWeekValue确实有第三个参数,并且图表确实重新计算了。这种方法的好处还有:您可以删除所有其他VBA事件管理。 -HTH

答案 5 :(得分:0)

我发现调用这个Sub工作......

Sub DoAllEvents()
    DoEvents
    DoEvents
End Sub

<强> BUT 微软警告说,在第一个DoEvents完成之前,下一个DoEvents会被执行,这可能会发生,这取决于调用之间没有延迟调用的频率。因此,DoEvents似乎充当一种不可屏蔽的中断,并且嵌套不可屏蔽的中断可以导致机器因多种原因而冻结,除了重启之外没有任何恢复。

  

(注意:如果一个人没有经常快速地调用上面的例程,嵌套可能不会   是一个问题。)

使用下面的Sub,我从他们的建议中修改,可以防止这种情况发生。

Sub DoAllEvents()
    On Error GoTo ErrorCheck
    Dim i
    For i = 1 To 4000    ' Start loop. Can be higher, MS sample shows 150000
        'I've found twice is enough, but only increased it to four or 4000.
        If i Mod 1000 = 0 Then     ' If loop has repeated 1000 times.
            DoEvents    ' Yield to operating system.
        End If
    Next i
    Exit Sub
ErrorCheck:
    Debug.Print "Error: "; Error, Err
    Resume Next
End Sub

我看来所需的DoEvents数量取决于您计算机上运行的后台任务的数量,更新图表似乎是应用程序的后台任务。我只需要两个DoEvent因为我经常调用例程;但是,如果需要的话,我可能会在以后提高它。 我还将Mod保持在1000,以便不像Microsoft建议的那样改变每个DoEvent之间的延迟,从而防止嵌套。如果您的系统不更新图表,您可能希望将数字从2000增加到更高的数字的一个可能原因。增加此数量允许机器处理DoEvents可能通过多次调用可能遇到的大量后台事件,因为它们可能在堆栈上,并且DoEvents事件只允许在将其在堆栈中的位置标记为之前运行特定数量的周期允许未处理的事件并返回,让它们在下次调用时处理。因此需要多次通话。将此更改为150000的示例似乎不会使机器运行太慢,为了安全起见,您可能需要将其设置为150000.

注意:第一个带有两个DoEvents的示例Sub可能是安全的,具体取决于您调用Sub的频率,但是,如果经常调用,您的计算机可能会冻结。你的来电。 ; - )

PS:如果你创建了很多嵌套循环并且程序没有按预期运行,那么DoEvents将成为你最好的调用之一。幸运的是,这在所有使用VBA的应用程序中都可用!

答案 6 :(得分:0)

运行Excel 2019。

在宏代码中添加了以下内容:

ActiveSheet.ChartObjects(1).Chart.Refresh    
DoEvents

图表现在在宏执行期间更新

答案 7 :(得分:0)

UDF getWeekValue 必须标记为易失性。

 Function getWeekValue (weekNumber As Integer, valuesRange As Range) As Integer   
 
 Application.Volatile '!!

 Dim aCell As Range  
 Dim currentDate As Date
 
 '... 

答案 8 :(得分:-2)

只是一个想法:在你的Worksheet_Change Sub中,插入第一行:

Application.EnableEvents = False

为了避免自我射击事件.... 当然,在Sub的结尾处将其设置回True。