Обновление диспетчера анимации и рисование кадров
Каждый раз, когда приложение планирует раскадровку, приложение должно предоставлять текущее время для диспетчера анимации. Текущее время также требуется при указании диспетчера анимации для обновления своего состояния и установки для всех переменных анимации соответствующих интерполированных значений.
Общие сведения
Анимация 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 не используется, необходимо также включить таймер, чтобы запустить его галочку.
Предыдущий шаг
Прежде чем приступить к этому шагу, необходимо выполнить следующий шаг: Создание переменных анимации.
Следующий шаг
После завершения этого шага следующий шаг: Чтение значений переменной анимации.
Связанные темы