【问题标题】:How to detect if painting last frame in buffered paint animation?如何检测是否在缓冲绘画动画中绘画最后一帧?
【发布时间】:2020-10-08 19:25:37
【问题描述】:

我在 WM_PAINT 期间使用BeginBufferedAnimation() 为自定义控件设置动画(交叉淡入淡出)。 我知道动画的第一帧何时绘制;当我使用 fUpdateTarget = TRUE 调用 EndBufferedAnimation() 时。 我可以通过检查来自BufferedPaintRenderAnimation() 的返回值来确定动画是否正在进行中。

问题是:我怎么知道动画的最后一帧是什么时候绘制的?

我找不到可以执行此操作的 API 调用。

想到的一件事是使用GetTickCount() 来确定自调用EndBufferedAnimation() 以来经过的时间,并对照BP_ANIMATIONPARAMS 结构的dwDuration 成员检查该时间。 但是,我不确定这种方法是否非常准确。

是否有另一种(万无一失)方法来确定 WM_PAINT 是否正在绘制动画的最后一帧?

编辑

显然,当动画通过调用BufferedPaintStopAllAnimations() 或使正在动画的客户区部分无效时过早停止时,检查已用时间不起作用。

编辑 2

这是我的(简化的)WM_PAINT 代码:

PAINTSTRUCT ps;

HDC DC = BeginPaint(Handle, &ps);

if (DC != NULL)
{
    // If animation in progress, paint the next frame.
    if (!BufferedPaintRenderAnimation(Handle, DC))
    {
        BP_ANIMATIONPARAMS ap = {sizeof(ap)};
        ap.style      = BPAS_LINEAR;
        ap.dwDuration = 1000;

        RECT R;

        GetClientRect(Handle, &R);

        HDC hdcFrom, hdcTo;

        HANIMATIONBUFFER Animation = BeginBufferedAnimation(Handle, DC, &R, BPBF_COMPATIBLEBITMAP, NULL, &ap, &hdcFrom, &hdcTo);

        if (Animation)
        {
            if (hdcFrom) Paint(hdcFrom, &R, OldState);
            if (hdcTo  ) Paint(hdcTo,   &R, NewState);

            // Paint the first frame.
            EndBufferedAnimation(Animation, true);
        }
        else
            Paint(DC, &R, NewState);
    }
    else
    {
        // Here, I want to check if BufferedPaintRenderAnimation() painted the last frame.
    }

    EndPaint(Handle, &ps);
}

编辑 3

我的自定义控件有一个子控件,需要与其父控件同步动画。为此,我通过在我的Paint() 方法中向子控件发送WM_PRINT 消息,让子控件将自己绘制到第一个和最后一个动画帧中。在绘制父控件后,子控件会收到其WM_PAINT 消息。为了防止父控件在动画时绘制子控件,我想在启动动画时隐藏子控件并在动画完成后再次显示它。

由于找不到万无一失的方法来检测动画何时结束,我决定不隐藏子控件。相反,我避免在调用EndBufferedAnimation() 之后以及当BufferedPaintRenderAnimation() 返回true 时使用RedrawWindow(ChildHandle, NULL, NULL, RDW_VALIDATE | RDW_NOFRAME) 重新绘制子控件。这边走, BufferedPaintRenderAnimation() 在动画结束时将子控件绘制为最终状态,因此子控件不必这样做。

【问题讨论】:

  • 使用animation manager,您可以通过SetManagerEventHandler 监控其statue。当状态从 BUSY 变为 IDLE 时,绘制最后一帧。
  • @RitaHan-MSFT 感谢您的回复。我认为IUIAnimationManager::GetStatus() 做同样的事情。不幸的是,这只告诉我所有动画是否都已完成。想象一下鼠标光标从一个控件移动到另一个控件。第一个控件仍然可以从“热”动画到“正常”,而第二个控件正在从“正常”动画到“热”。仅当两个动画都完成后,状态才会变为“空闲”。如果鼠标光标一直在控件上移动,这可能需要很长时间。
  • 对于多个动画,您可以使用Storyboard,它可以管理多个过渡。过渡定义了单个动画变量在特定时间间隔内如何变化。
  • @RitaHan-MSFT 看起来IUIAnimationStoryboard::GetStatus() 可以产生我正在寻找的动画状态。下一个问题是:如何获取以BeginBufferedAnimation()开头的动画关联的IUIAnimationStoryboard接口?我只有一个HANIMATIONBUFFER 句柄。
  • 您可以保留一个标志,以记住 BufferedPaintRenderAnimation 在上一个绘制周期中返回的内容。当它从true 变为false 时,缓冲动画就完成了。

标签: c++ winapi


【解决方案1】:

我找到了解决问题的更好方法。

参见编辑 3。

【讨论】:

    猜你喜欢
    • 2015-09-06
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 2017-07-25
    • 2017-06-16
    相关资源
    最近更新 更多