更新動畫管理員和繪製畫面格

每次應用程式排程分鏡腳本時,應用程式都必須提供目前的時間給動畫管理員。 當指示動畫管理員更新其狀態,並將所有動畫變數設定為適當的插補值時,也需要目前的時間。

概觀

Windows 動畫支援兩種設定:應用程式驅動動畫和計時器驅動動畫。

若要在應用程式中使用應用程式驅動動畫,您必須先更新動畫管理員,再繪製每個畫面格,並使用適當的機制來經常繪製畫面格,以便動畫使用。 使用應用程式驅動動畫的應用程式可以使用任何機制來判斷目前的時間,但 Windows 動畫計時器物件會以動畫管理員接受的單位傳回精確的時間。 為了避免在未播放任何動畫時進行不必要的繪製,您也應該提供管理員事件處理常式,在排程動畫時開始重新繪製,並在每個畫面格之後檢查是否可以暫停重繪。 如需詳細資訊,請參閱 應用程式驅動動畫

在應用程式驅動設定中,應用程式可以呼叫 IUIAnimationManager::GetStatus 方法,以確認動畫目前已排程,並繼續繪製畫面格。 因為重繪會在沒有排程動畫時停止,所以必須在下次排程動畫時重新開機它。 應用程式可以註冊管理員事件處理常式,以在動畫管理員的狀態從閒置變更時收到通知, (目前未排程任何動畫) 忙碌中。

若要在應用程式中使用計時器驅動動畫,您必須將動畫管理員連接到動畫計時器,並提供計時器事件處理常式。 當動畫管理員連接到計時器時,計時器可以告知管理員何時應該在進行時間時更新動畫狀態。 應用程式應該為每個計時器刻度繪製框架。 動畫管理員可以接著告訴計時器何時播放動畫,因此計時器可以在不必要的重繪期間關閉本身。 若要避免在未播放任何動畫時不必要的繪圖,您應該設定計時器自動停用本身。 如需詳細資訊,請參閱 計時器驅動動畫

範例程式碼

Application-Driven動畫

下列範例程式碼取自 Windows 動畫範例 Application-Driven AnimationGrid Layout的 ManagerEventHandler.h。 它會定義管理員事件處理常式。

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

    ...

};

下列範例程式碼取自 Windows 動畫範例 Application-Driven Animation的 MainWindow.cpp;請參閱 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();
}

因為管理員事件處理常式會保留主視窗物件的參考,所以應該透過將 Null 傳遞至 SetManagerEventHandler () 來清除管理員事件處理常式,否則應該在終結主視窗之前完全釋放動畫管理員。

下列範例程式碼取自 Windows 動畫範例 Application-Driven Animation中的 MainWindow.cpp;請參閱 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
        );

    ...

}

下列範例程式碼取自 Windows 動畫範例 Application-Driven AnimationGrid Layout的 MainWindow.cpp;請參閱 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動畫

下列範例程式碼取自 Windows 動畫範例 TimerEventHandler.h TimerEventHandler.h。 此範例程式碼會定義計時器事件處理常式,使視窗的工作區失效,以在每次更新動畫狀態之後重新繪製。

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

    ...

};

下列範例程式碼取自 Windows 動畫範例 Timer-Driven Animation的 MainWindow.cpp;請參閱 CMainWindow::InitializeAnimation。 此範例會使用 CreateInstance 方法建立計時器事件處理常式的實例,並使用 IUIAnimationTimer::SetTimerEventHandler 方法將它傳遞給計時器。 因為計時器事件處理常式會保留主視窗物件的參考,所以應該將 Null 傳遞至 SetTimerEventHandler () 或計時器完全釋放,以清除計時器事件處理常式,再終結主視窗。

// Create and set the timer event handler

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

下列範例程式碼取自 Windows 動畫範例 Timer-Driven Animation中的 MainWindow.cpp;請參閱 CMainWindow::InitializeAnimation 方法。 它會在動畫管理員物件上呼叫QueryInterface方法,以取得IUIAnimationTimerUpdateHandler 的指標,然後使用 IUIAnimationTimerUpdateHandler方法將動畫管理員設定為計時器的更新處理常式,以連接UIAnimationManagerUIAnimationTimer物件。 請注意,不需要明確清除此連線;應用程式釋放動畫管理員和動畫計時器之後,會安全地清除連線。

// 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 動畫概觀