Обновление диспетчера анимации и рисование кадров

Каждый раз, когда приложение планирует раскадровку, приложение должно предоставлять текущее время для диспетчера анимации. Текущее время также требуется при указании диспетчера анимации для обновления своего состояния и установки для всех переменных анимации соответствующих интерполированных значений.

Общие сведения

Анимация Windows поддерживает две конфигурации: анимация на основе приложений и анимация на основе таймера.

Чтобы использовать анимацию на основе приложения, необходимо обновить диспетчер анимации перед рисованием каждого кадра и использовать соответствующий механизм для рисования кадров достаточно часто для анимации. Приложение, использующее анимацию на основе приложения, может использовать любой механизм для определения текущего времени, но объект таймера анимации Windows возвращает точное время в единицах, принятых диспетчером анимации. Чтобы избежать ненужного рисования, если анимация не воспроизводится, необходимо также предоставить обработчик событий диспетчера, чтобы начать перерисовку при планировании анимации и проверка после каждого кадра, можно ли приостановить перерисовку. Дополнительные сведения см. в разделе Анимация на основе приложений.

В управляемой приложением конфигурации может вызвать метод IUIAnimationManager::GetStatus , чтобы убедиться, что анимация запланирована в настоящее время, и продолжить рисование кадров, если они есть. Так как перерисовка прекращается, когда анимация не запланирована, ее необходимо перезапустить при следующем запланированном выполнении анимации. Приложение может зарегистрировать обработчик событий диспетчера, чтобы получать уведомления о том, что состояние диспетчера анимации изменится с простоя (в настоящее время анимация не запланирована) на занято.

Чтобы использовать анимацию на основе таймера в приложении, необходимо подключить диспетчер анимации к таймеру анимации и предоставить обработчик событий таймера. Когда диспетчер анимации подключен к таймеру, таймер может сообщить диспетчеру, когда состояние анимации должно обновляться по мере выполнения времени. Приложение должно нарисовать кадр для каждого такта таймера. Диспетчер анимации, в свою очередь, может сообщить таймеру о том, когда воспроизводится анимация, чтобы таймер может отключиться во время простоя, когда перерисовка не требуется. Чтобы избежать ненужного рисования, если анимация не воспроизводится, следует настроить автоматическое отключение таймера. Дополнительные сведения см. в разделе Анимация на основе таймера.

Пример кода

Анимация Application-Driven

Следующий пример кода взят из ManagerEventHandler.h из примеров анимации Windows Анимация на основе приложений и макет сетки. Он определяет обработчик событий диспетчера.

#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;
    }

    ...

};

Следующий пример кода взят из MainWindow.cpp из примера анимации Windows Application-Driven Animation. см. раздел CMainWindow::InitializeAnimation. В этом примере создается экземпляр обработчика событий диспетчера с помощью метода CreateInstance и передается диспетчеру анимации с помощью метода 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();
}

Так как обработчик событий диспетчера сохраняет ссылку на объект окна main, обработчик событий диспетчера должен быть очищен (путем передачи NULLв SetManagerEventHandler) или диспетчер анимации должен быть полностью освобожден до уничтожения окна main.

Следующий пример кода взят из MainWindow.cpp в примере анимации Windows Application-Driven Animation. см. метод CMainWindow::OnPaint. Он вызывает метод IUIAnimationManager::GetTime для получения времени в единицах, необходимых методу 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
        );

    ...

}

Следующий пример кода взят из MainWindow.cpp из примеров анимации Windows Анимация на основе приложений и макет сетки. см. метод CMainWindow::OnPaint. Предполагается, что приложение использует графический API, который автоматически синхронизируется с частотой обновления монитора (например, Direct2D с параметрами по умолчанию). В этом случае достаточно вызова функции InvalidateRect , чтобы убедиться, что код рисования будет вызван снова, когда придет время нарисовать следующий кадр. Вместо безусловного вызова InvalidateRect лучше проверка, если все еще есть анимация, запланированная с помощью 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
                );
        }
    }
}

Анимация Timer-Driven

Следующий пример кода взят из TimerEventHandler.h из примера анимации Windows На основе анимации с помощью таймера. В примере кода определяется обработчик событий таймера, который делает недействительной клиентскую область окна, чтобы вызвать перекраску после каждого обновления состояния анимации.

#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;
    }

    ...

};

Следующий пример кода взят из MainWindow.cpp из примера анимации Windows На основе таймера. см. раздел CMainWindow::InitializeAnimation. В этом примере создается экземпляр обработчика событий таймера с помощью метода CreateInstance и передается таймеру с помощью метода IUIAnimationTimer::SetTimerEventHandler . Так как обработчик событий таймера сохраняет ссылку на объект окна main, обработчик событий таймера должен быть очищен (путем передачи NULLв SetTimerEventHandler) или полностью освобожден перед уничтожением окна main.

// Create and set the timer event handler

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

Следующий пример кода взят из MainWindow.cpp в примере анимации Windows На основе таймера. см. метод CMainWindow::InitializeAnimation. Он вызывает метод QueryInterface для объекта диспетчера анимации, чтобы получить указатель на IUIAnimationTimerUpdateHandler, а затем соединяет объекты UIAnimationManager и UIAnimationTimer , задавая диспетчер анимации в качестве обработчика обновления таймера с помощью метода IUIAnimationTimer::SetTimerUpdateHandler . Обратите внимание, что нет необходимости явно очищать это соединение; подключение будет безопасно очищено после того, как приложение отпустит диспетчер анимации и таймер анимации.

// 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

        ...

    }
}

Если UI_ANIMATION_IDLE_BEHAVIOR_DISABLE не используется, необходимо также включить таймер, чтобы запустить его галочку.

Предыдущий шаг

Прежде чем приступить к этому шагу, необходимо выполнить следующий шаг: Создание переменных анимации.

Следующий шаг

После завершения этого шага следующий шаг: Чтение значений переменной анимации.

IUIAnimationManager::GetStatus

IUIAnimationManager::SetManagerEventHandler

IUIAnimationManager::Update

IUIAnimationTimer::GetTime

IUIAnimationTimer::SetTimerUpdateHandler

UIAnimationManager

UIAnimationTimer

Обзор анимации Windows