首页 > 解决方案 > 组合框仅在宏结束后显示值

问题描述

我有一个包含一些图表和许多组合框(activex 控件)的应用程序。当用户更改任何组合框的值时,图表都会更新。这里没问题。

所以,我编写了一个代码来将应用程序的整个屏幕导出为图像。这用于模拟几个场景。

但是,这里是问题开始的地方。

此代码中有一些“for...next”循环来更改这些组合框的值。导出图像时,图表会按预期更新,但组合框不会更改其值。它们在每种情况下都显示相同的值,即使图表正在更新。

所以,问题是:有没有办法在代码结束之前刷新组合框的值?

Sub example()

For Each elem In myArray

    Sheets("App").ComboBox1.Value = elem

    Sheets("Temp").Shapes.AddChart

    Set cht = Sheets("Temp").ChartObjects(1)

    Sheets("App").Range("A1:AM103").CopyPicture Appearance:=xlScreen, Format:=xlBitmap

    With cht.Chart
        .Paste
        .export Filename:="test.jpg", FilterName:="jpg"
        .Parent.Delete
    End With

Next

End Sub

标签: excelvbacombobox

解决方案


解释

首先,恭喜:您在这里发现了一个非常烦人的错误。我试图重现你的问题,我可以很容易地做到这一点。

  • 如果在更新组合框后设置断点(即线程暂停)=> ActiveX 组件被刷新
  • 如果您设置一个Application.Wait (TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 5))(即您在视觉上停止执行 5 秒,但从技术上讲线程仍在运行)=> 您可以清楚地看到 ActiveX 组件没有更新,这就是您的图像生成错误的原因。

我已经尝试了所有明显的技巧(Application.ScreenUpdating = True, DoEvents,等) Application.EnableEvents = TrueApplication.Calculate但无论如何都没有成功。

似乎只有在 VBA 线程结束时,Microsoft Excel 才会刷新 ActiveX 组件。哇。

我能想到的解决这个错误的唯一方法

我能想到的在更新 ActiveX 组件后从技术上停止执行并稍后恢复它的唯一方法是使用Application.OnTimeExcel 的方法:

Application.OnTime安排一个程序在未来的特定时间运行(在一天中的特定时间或经过特定时间量之后)。

对于从技术角度来看它看起来有多丑,您可以更新您的组合框,然后安排其余代码在您完成后一秒钟发生。从技术角度来看:

  • VBA 线程 1:更新您的 ComboBox 并结束 => ActiveX 组件被刷新
  • 没有 VBA 线程的 1 秒暂停。
  • VBA 线程 2:使用更新的 ActiveX 组件创建图表并导出图像。

实际上,您的代码看起来像这样:

Dim myArray(2) 'declare your array as global so that it can be accessed by all the macros - in my example I assume it contains 3 elements
Dim currentElem As Integer 'declare this index as global so it remains in memory even after the code ended execution

Sub example()

    'call this macro.
    'you first initialize your values:
    myArray(0) = "test 1"
    myArray(1) = "test 2"
    myArray(2) = "test 3"
    currentElem = 0
    'and then call the first update of your activeX component
    first_step_set_activeX

End Sub

Sub first_step_set_activeX()

    If currentElem < UBound(myArray) Then
        'for each element not treated yet
        '(that's why the If currentElem < UBound(myArray)
        elem = myArray(currentElem) 'get current element from array
        Sheets("App").ComboBox1.Value = elem 'update your ActiveX component
        currentElem = currentElem + 1 'increase the currentElem index
        Application.OnTime TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 1), "second_step_make_chart_and_print" 'schedule the call of the printing part
    End If

End Sub

Sub second_step_make_chart_and_print()

    'here do the job of the printing part
    Sheets("Temp").Shapes.AddChart

    Set cht = Sheets("Temp").ChartObjects(1)

    Sheets("App").Range("A1:AM103").CopyPicture Appearance:=xlScreen, Format:=xlBitmap

    With cht.Chart
        .Paste
        .Export Filename:="test.jpg", FilterName:="jpg"
        .Parent.Delete
    End With

    'and reschedule the call for the next activeX component
    Application.OnTime TimeSerial(Hour(Now()), Minute(Now()), Second(Now()) + 1), "first_step_set_activeX"

End Sub

推荐阅读