4

我在 Excel VBA 中编写了一些简单的代码,以使范围“闪烁”一种颜色 - 这是通过在相关范围上仔细绘制一个矩形对象并改变其透明度以使框逐渐消失来实现的。

这是代码(Sheet1用于Worksheet_Change事件):

Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private Sub flashBox(ByVal area As Range, Optional ByVal fillColour As MsoRGBType = vbGreen)

    Const animationSeconds As Single = 0.5
    Const animationSteps As Long = 20

    With area.Worksheet.Shapes.AddShape(msoShapeRectangle, area.Left, area.Top, _
                                        Application.WorksheetFunction.Min(area.Width, 1000), _
                                        Application.WorksheetFunction.Min(area.Height, 1000)) 'stop infinite boxes, could use view area to define this
        .Line.Visible = msoFalse
        .Fill.ForeColor.RGB = fillColour
        Dim i As Long
        For i = 1 To animationSteps
            Sleep animationSeconds * 1000 / animationSteps
            .Fill.Transparency = i / animationSteps
            DoEvents 'screen repaint
        Next i
        .Delete
    End With
End Sub

Private Sub Worksheet_Change(ByVal Target As Range)
    flashBox Target, ColorConstants.vbMagenta
End Sub

我使用一个With块来包含没有父变量的临时对象(我认为它非常整洁,并希望保持这种方式)。问题来自DoEvents调用(需要强制为动画重新绘制屏幕)。

动画是从某些工作表更改事件中调用的,如果调用了 sub 的第二个实例(或者实际上似乎发生了任何事件),第一个实例将被终止半完整,并且永远不会完成 - 这意味着永远不会删除临时形状.

这是一个插图,显示了我在说什么: 演示 Gif

我该如何解决这个问题?

4

1 回答 1

2

与其说是解决方案,不如说是一种锻炼,但从技术上讲,它可以完成工作

如果您在程序运行期间禁用用户输入flashbox,它将等待动画完成,然后才重新启用它,您可以避免动画保持冻结状态

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.Interactive = False
    flashBox Target, ColorConstants.vbMagenta
    Application.Interactive = True
End Sub

在此处输入图像描述

我会看看我是否可以“正确”解决这个问题,但现在最后这是一个很好的解决方法:)

于 2019-05-11T20:24:08.720 回答