刷新所有图表而不闪烁

时间:2015-02-18 11:48:19

标签: excel vba excel-vba

目的是在重新计算单元格后刷新Excel中的所有图表。

我使用Microsoft Excel 2010。

众所周知,有一个错误?在Excel中,即使在

之后Excel也不会更新图表
Application.CalculateFullRebuild

一个已知的黑客行为是这样的:

Application.ScreenUpdating = False
Temp = ActiveCell.ColumnWidth
ActiveCell.Columns.AutoFit
ActiveCell.ColumnWidth = Temp
Application.ScreenUpdating = True

这确实有效。但是,所有Excel图表都会闪烁(更新时它们会变白)。你能告诉我,有没有办法避免这种眨眼?

我试着打电话

.Refresh
所有图表上的

https://msdn.microsoft.com/en-us/library/office/ff198180(v=office.14).aspx):

For Each ChartObject In ActiveSheet.ChartObjects
    ChartObject.Refresh
Next

但由于某种原因,我的Excel(2010)显示错误#438“对象不支持此属性或方法”。

请问,请问,我是否会错过重要的事情?

5 个答案:

答案 0 :(得分:8)

未经测试 .Refresh 可能适用于此:

Sub ChangeCharts()
Application.ScreenUpdating = False 'This line disable the on screen update for better performance, the blink you see, you could delete both lanes but it will run slower
Dim myChart As ChartObject
For Each myChart In ActiveSheet.ChartObjects
    myChart.Chart.Refresh
Next myChart
Application.ScreenUpdating = True'This line reenable the on screen update for better performance, the blink you see, you could delete both lanes but it will run slower
End Sub

这是因为(正如您提供的链接所示) .Refresh 仅适用于对象图表而不适用​​于对象 ChartObjects < / strong>因为你一直试图应用它。希望它能引导你朝着正确的方向前进。 (还在代码中添加了屏幕上闪烁/闪烁的引号)

答案 1 :(得分:3)

Pi日快乐!

我只是做了一些动画图表实验,使用VBA更改单元格中的计数器,并使用工作表公式基于该计数器重新计算图表数据。

在Excel 97-2003的时候,我曾经做过很多图表动画,并且它们运行得很好。当Excel 2007推出时,动画确实降级了,似乎没有任何帮助。但是,现在我在最新版本的Office 365(版本1904,内部版本11504)中做了这些测试。事实证明,过去几年左右的某个时候,Microsoft使它运行得更好。

Sub ChartAnimation1()
  Dim i As Double
  For i = 0 To 1000 Step 50
    ActiveSheet.Range("Stepper") = i
  Next
End Sub

动画没有动画,也就是说,尽管数据改变了,但图表也没有改变。

我的经验告诉我,在更改单元格的值后,我应该在代码中放入类似DoEvents的内容。

Sub ChartAnimation2()
  Dim i As Double
  For i = 0 To 1000 Step 50
    ActiveSheet.Range("Stepper") = i
    DoEvents
  Next
End Sub

这有所帮助,图表发生了变化,但是动画并不流畅。错过了一些步骤,其效果是一个生涩的动画。

Sub ChartAnimation3()
  Dim i As Double
  For i = 0 To 1000 Step 50
    ActiveSheet.Range("Stepper") = i
    DoEvents
    DoEvents
  Next
End Sub

与运行DoEvents相比,运行速度要慢一些,但是运行起来更加顺畅。仍然不完美,但是还不错。

两个以上的DoEvents是过大的:代码花费相同的时间长度,并且动画没有任何平滑度。

我还尝试了Chart.RefreshChart.ActivateScreenUpdating的各种组合。两点:

  • 在没有DoEvents的情况下,无论我尝试了什么其他操作,动画都无法播放。
  • 通过几个DoEvents,这些额外的步骤都无法使动画更加流畅,但可以使动画明显变慢。

这很有趣,所以有一天我会写博客。完成后,我会回来并发布链接。

答案 2 :(得分:1)

在打开有关Excel ScreenUpdating后,有关闪烁或闪烁的Excel图表的VB.NET查询之后,通常将我发送到此VBA帖子。图表闪烁一直使我生气很久了,我没有看到任何可行的解决方案,包括上面看起来应该可行但不能解决的问题。现在,我找到了一个对所有程序都可以100%工作的解决方案。由于这是VBA帖子,因此我为闪烁的图表显示了VBA解决方案,但是我的VB.NET解决方案适用于发送到该帖子中寻找VB.NET解决方案的其他任何人。我的解决方案基于上面Zegad的回答,但是它有一些重要的补充内容,这些补充内容尚未记录,在我看来并不明显。使用以下子项代替“ MyXLApp.ScreenUpdating = True”。如果您发现它适合您,请不要要求我解释它为什么起作用。我敢肯定,这里有很多人可以解释这一点,但对我来说,这是运气和顽强决心的结果。奇怪的是,您实际上只需要激活并刷新然后再停用任何一个图表,并且重新启用后,所有图表将更新而不会闪烁,请参见下面的“ VB.NET CODE-2子”。

Sub ScrUpdateEnableNoFlicker()'VBA CODE
    Dim myChartObj As ChartObject
    For Each myChartObj In ActiveSheet.ChartObjects
        myChartObj.Activate 'IMPORTANT ADDITION
        myChartObj.Chart.Refresh
    Next
    Cells.Range("A1").Select 'IMPORTANT ADDITION
    Application.ScreenUpdating = True
End Sub

Private Sub ScrUpdateEnableNoFlicker() 'VB.NET CODE-1
    'BEFORE TURNING SCREEN UPDATING BACK ON...
    'ACTIVATE and refresh the chart objects on the sheet with the charts.
    Dim aSheet As Excel.Worksheet = CType(mXLWrkbk.Sheets("Sheet1"), Excel.Worksheet)
    Dim aChartObjects As Excel.ChartObjects = CType(aSheet.ChartObjects, Excel.ChartObjects)
    For Each achartobject As Excel.ChartObject In aChartObjects
        achartobject.Activate() 'IMPORTANT - Will not work without activating first
        Dim achart As Excel.Chart = achartobject.Chart
        achart.Refresh()
    Next
    'Now deactivate the current activated chart object by selecting any cell
    'THIS IS IMPORTANT - It will not work without doing this
    Dim selRange As Excel.Range = aSheet.Range("A1")
    selRange.Select()
    'Now turn Screen Updating back on...
    'All of the Charts will have updated and will not flicker
    mXLApp.ScreenUpdating = True
End Sub

Private Sub ScrUpdateEnableNoFlicker() 'VB.NET CODE-2
    'BEFORE TURNING SCREEN UPDATING BACK ON...
    'ACTIVATE ANY ONE of the chart objects on the sheet with the charts.
    Dim aSheet As Excel.Worksheet = CType(mXLWrkbk.Sheets("Sheet1"), Excel.Worksheet)
    Dim aChartObject As Excel.ChartObject = CType(aSheet.ChartObjects("Chart 9"), Excel.ChartObject)
    aChartObject.Activate() 'IMPORTANT - Will not work without activating first
    'Refresh just the ONE activated chart.
    Dim aChart As Excel.Chart = aChartObject.Chart
    aChart.Refresh()
    'Now deactivate the current activated chart object by selecting any cell
    'THIS IS IMPORTANT - It will not work without doing this
    Dim selRange As Excel.Range = aSheet.Range("A1")
    selRange.Select()
    'Now turn Screen Updating back on...
    'You only need to activate/deactivate any one chart and all of the Charts will have updated and will not flicker
    mXLApp.ScreenUpdating = True
End Sub

答案 3 :(得分:0)

隐藏或显示图表中的序列时遇到此问题。直到我向下滚动然后再次返回到图表时,更改才会变得明显,这确实很痛苦。我尝试了上述所有解决方案,但没有运气,直到意识到在进行更改之前可以取消选择并再次选择图表。

myChart.TopLeftCell.Select

myChart.Select

...

祝您研究工作顺利;)

答案 4 :(得分:0)

感谢之前在这里发帖的人!如果没有您的成功,我将无法获得流畅的动态模拟动画。就我而言,它是一个 xlXYScatterLinesNoMarkers 类型的图表。在 VBA 中运行。

以编程方式更改系列时,这对我有用。图表动画流畅。运行 Excel 2016 64 位

Public Sub ShowOneAnimationFrame(worksheetName As String, chartName As String, _
                                 xvals() As Double, yvals() As Double)

    'update chart series programmatically
    'Excel 2016 64bit
    'Dec 21, 2020
    'Author:  S^3
    
    Dim theChart As chart
    Dim chrtObj As ChartObject
    Dim oneSeries As Series
    
    Set chrtObj = Sheets(worksheetName).ChartObjects(chartName)
    Set theChart = chrtObj.chart
    
    If theChart.SeriesCollection.Count = 0 Then
        theChart.SeriesCollection.NewSeries
    End If
    Set oneSeries = theChart.SeriesCollection(1)
    
    'update the series with new values
    oneSeries.XValues = xvals
    oneSeries.Values = yvals
    
    theChart.Refresh  'required (this and the next line are required but the order doesn't matter)
    chrtObj.Select    'required
    Cells.Range("A1") = Cells.Range("A1").value  'something like this is required
    
End Sub