Actualizar el Administrador de animaciones y dibujar fotogramas

Cada vez que una aplicación programa un guión gráfico, la aplicación debe proporcionar la hora actual al administrador de animaciones. La hora actual también es necesaria al dirigir al administrador de animaciones para actualizar su estado y establecer todas las variables de animación en los valores interpolados adecuados.

Información general

Hay dos configuraciones compatibles con la animación de Windows: animación controlada por aplicaciones y animación controlada por temporizador.

Para usar la animación controlada por aplicaciones en la aplicación, debe actualizar el administrador de animaciones antes de dibujar cada fotograma y usar un mecanismo adecuado para dibujar fotogramas con frecuencia suficiente para la animación. Una aplicación que usa animaciones controladas por aplicaciones puede usar cualquier mecanismo para determinar la hora actual, pero el objeto del temporizador de animación de Windows devuelve un tiempo preciso en las unidades aceptadas por el administrador de animaciones. Para evitar dibujos innecesarios cuando no se reproduce ninguna animación, también debe proporcionar un controlador de eventos de administrador para empezar a dibujar cuando se programan animaciones y comprobar después de cada fotograma si se puede suspender el dibujo. Para obtener más información, consulte Animación controlada por aplicaciones.

En la configuración controlada por la aplicación, una aplicación puede llamar al método IUIAnimationManager::GetStatus para comprobar que las animaciones están programadas actualmente y seguir dibujando fotogramas si son. Dado que el volver a dibujar se detiene cuando no hay animaciones programadas, es necesario reiniciarla la próxima vez que se programe una animación. Una aplicación puede registrar un controlador de eventos de administrador para recibir una notificación cuando el estado del administrador de animaciones cambia de inactivo (actualmente no hay animaciones programadas) a ocupados.

Para usar la animación controlada por temporizador en la aplicación, debe conectar el administrador de animaciones a un temporizador de animación y proporcionar un controlador de eventos de temporizador. Cuando el administrador de animaciones está conectado a un temporizador, el temporizador puede indicar al administrador cuándo debe actualizarse el estado de animación a medida que avanza el tiempo. La aplicación debe dibujar un fotograma para cada tic del temporizador. A su vez, el administrador de animaciones puede indicar al temporizador cuándo se reproducen animaciones, por lo que el temporizador puede apagarse durante períodos de inactividad cuando no es necesario volver a dibujar. Para evitar dibujos innecesarios cuando no se reproduce ninguna animación, debe configurar el temporizador para deshabilitarse automáticamente. Para obtener más información, vea Animación controlada por temporizador.

Código de ejemplo

Animación de Application-Driven

El código de ejemplo siguiente se toma de ManagerEventHandler.h de los ejemplos de animación de Windows Animación controlada por aplicaciones y Diseño de cuadrícula. Define el controlador de eventos del administrador.

#include "UIAnimationHelper.h"

// Event handler object for manager status changes

class CManagerEventHandler :
    public CUIAnimationManagerEventHandlerBase<CManagerEventHandler>
{
public:

    static HRESULT
    CreateInstance
    (
        CMainWindow *pMainWindow,
        IUIAnimationManagerEventHandler **ppManagerEventHandler
    ) throw()
    {
        CManagerEventHandler *pManagerEventHandler;
        HRESULT hr = CUIAnimationCallbackBase::CreateInstance(
            ppManagerEventHandler,
            &pManagerEventHandler
            );
        if (SUCCEEDED(hr))
        {
            pManagerEventHandler->m_pMainWindow = pMainWindow;
        }
        
        return hr;
    }

    // IUIAnimationManagerEventHandler

    IFACEMETHODIMP
    OnManagerStatusChanged
    (
        UI_ANIMATION_MANAGER_STATUS newStatus,
        UI_ANIMATION_MANAGER_STATUS previousStatus
    )
    {
        HRESULT hr = S_OK;

        if (newStatus == UI_ANIMATION_MANAGER_BUSY)
        {
            hr = m_pMainWindow->Invalidate();
        }

        return hr;
    }

    ...

};

El siguiente código de ejemplo se toma de MainWindow.cpp del ejemplo de animación de Windows Animación Animación controlada por aplicaciones; vea CMainWindow::InitializeAnimation. En este ejemplo se crea una instancia del controlador de eventos del administrador mediante el método CreateInstance y se pasa al administrador de animaciones mediante el método IUIAnimationManager::SetManagerEventHandler .

// Create and set the ManagerEventHandler to start updating when animations are scheduled

IUIAnimationManagerEventHandler *pManagerEventHandler;
HRESULT hr = CManagerEventHandler::CreateInstance(
    this,
    &pManagerEventHandler
    );
if (SUCCEEDED(hr))
{
    hr = m_pAnimationManager->SetManagerEventHandler(
        pManagerEventHandler
        );
    pManagerEventHandler->Release();
}

Dado que el controlador de eventos del administrador conserva una referencia al objeto de ventana principal, el controlador de eventos del administrador debe borrarse (pasando NULL a SetManagerEventHandler) o el administrador de animaciones debe liberarse completamente antes de que se destruya la ventana principal.

El siguiente código de ejemplo se toma de MainWindow.cpp en la animación de ejemplo animación de Windows Animación basada en aplicaciones; vea el método CMainWindow::OnPaint. Llama al método IUIAnimationManager::GetTime para recuperar la hora de las unidades requeridas por el método IUIAnimationManager::Update .

// Update the animation manager with the current time

UI_ANIMATION_SECONDS secondsNow;
HRESULT hr = m_pAnimationTimer->GetTime(
    &secondsNow
    );

if (SUCCEEDED(hr))
{
    hr = m_pAnimationManager->Update(
        secondsNow
        );

    ...

}

El siguiente código de ejemplo se toma de MainWindow.cpp de los ejemplos de animación de Windows Animación controlada por aplicaciones y Diseño de cuadrícula; vea el método CMainWindow::OnPaint. Se supone que la aplicación usa una API de gráficos que se sincroniza automáticamente con la frecuencia de actualización del monitor (por ejemplo, Direct2D con su configuración predeterminada), en cuyo caso una llamada a la función InvalidateRect es suficiente para asegurarse de que se volverá a llamar al código de dibujo cuando sea el momento de dibujar el siguiente fotograma. En lugar de llamar a InvalidateRect incondicionalmente, es mejor comprobar si todavía hay alguna animación programada mediante GetStatus.

// Read the values of the animation variables and draw the client area

hr = DrawClientArea();
if (SUCCEEDED(hr))
{          
    // Continue redrawing the client area as long as there are animations scheduled
    UI_ANIMATION_MANAGER_STATUS status;
    hr = m_pAnimationManager->GetStatus(
        &status
        );
    if (SUCCEEDED(hr))
    {
        if (status == UI_ANIMATION_MANAGER_BUSY)
        {
            InvalidateRect(
                m_hwnd,
                NULL,
                FALSE
                );
        }
    }
}

Animación de Timer-Driven

El siguiente código de ejemplo se toma de TimerEventHandler.h de la animación de ejemplo de Animación de Windows Animación controlada por temporizador. El código de ejemplo define el controlador de eventos del temporizador, que invalida el área cliente de la ventana para provocar un reintentos después de cada actualización del estado de animación.

#include "UIAnimationHelper.h"

// Event handler object for timer events

class CTimerEventHandler :
    public CUIAnimationTimerEventHandlerBase<CTimerEventHandler>
{
public:

    static HRESULT
    CreateInstance
    (
        CMainWindow *pMainWindow,
        IUIAnimationTimerEventHandler **ppTimerEventHandler
    ) throw()
    {
        CTimerEventHandler *pTimerEventHandler;
        HRESULT hr = CUIAnimationCallbackBase::CreateInstance(
            ppTimerEventHandler,
            &pTimerEventHandler
            );

        if (SUCCEEDED(hr))
        {
            pTimerEventHandler->m_pMainWindow = pMainWindow;
        }
        
        return hr;
    }

    // IUIAnimationTimerEventHandler

    IFACEMETHODIMP
    OnPreUpdate()
    {
        return S_OK;
    }

    IFACEMETHODIMP
    OnPostUpdate()
    {
        HRESULT hr = m_pMainWindow->Invalidate();

        return hr;
    }

    IFACEMETHODIMP
    OnRenderingTooSlow
    (
        UINT32 /* fps */
    )
    {
        return S_OK;
    }

    ...

};

El siguiente código de ejemplo se toma de MainWindow.cpp de la animación de ejemplo de Animación de Windows Animación controlada por temporizador; vea CMainWindow::InitializeAnimation. En este ejemplo se crea una instancia del controlador de eventos del temporizador mediante el método CreateInstance y se pasa al temporizador mediante el método IUIAnimationTimer::SetTimerEventHandler . Dado que el controlador de eventos del temporizador conserva una referencia al objeto de ventana principal, se debe borrar el controlador de eventos del temporizador (pasando NULL a SetTimerEventHandler) o el temporizador completamente liberado antes de que se destruya la ventana principal.

// Create and set the timer event handler

IUIAnimationTimerEventHandler *pTimerEventHandler;
hr = CTimerEventHandler::CreateInstance(
    this,
    &pTimerEventHandler
    );
if (SUCCEEDED(hr))
{
    hr = m_pAnimationTimer->SetTimerEventHandler(
        pTimerEventHandler
        );
    pTimerEventHandler->Release();
}

El código de ejemplo siguiente se toma de MainWindow.cpp en la animación de ejemplo de Animación de Windows Animación controlada por temporizador; vea el método CMainWindow::InitializeAnimation. Llama al método QueryInterface en el objeto del administrador de animaciones para obtener un puntero a IUIAnimationTimerUpdateHandler y, a continuación, conecta los objetos UIAnimationManager y UIAnimationTimer estableciendo el administrador de animaciones como controlador de actualización del temporizador mediante el método IUIAnimationTimer::SetTimerUpdateHandler . Tenga en cuenta que no es necesario borrar explícitamente esta conexión; La conexión se borra de forma segura después de que la aplicación suelte el administrador de animaciones y el temporizador de animación.

// Connect the animation manager to the timer

IUIAnimationTimerUpdateHandler *pTimerUpdateHandler;
hr = m_pAnimationManager->QueryInterface(
    IID_PPV_ARGS(&pTimerUpdateHandler)
    );

if (SUCCEEDED(hr))
{
    hr = m_pAnimationTimer->SetTimerUpdateHandler(
        pTimerUpdateHandler
        UI_ANIMATION_IDLE_BEHAVIOR_DISABLE  // timer will shut itself off when there are no animations playing
        );
    pTimerUpdateHandler->Release();
    if (SUCCEEDED(hr))
    {
        // Create and set the timer event handler

        ...

    }
}

Si no se usa UI_ANIMATION_IDLE_BEHAVIOR_DISABLE, también es necesario habilitar el temporizador para iniciarlo.

Paso anterior

Antes de comenzar este paso, debe haber completado este paso: Crear variables de animación.

siguiente paso

Después de completar este paso, el siguiente paso es: Leer los valores de las variables de animación.

IUIAnimationManager::GetStatus

IUIAnimationManager::SetManagerEventHandler

IUIAnimationManager::Update

IUIAnimationTimer::GetTime

IUIAnimationTimer::SetTimerUpdateHandler

UIAnimationManager

UIAnimationTimer

Información general sobre la animación de Windows