アニメーション マネージャと描画フレームを更新する

アプリケーションがストーリーボードをスケジュールするたびに、アプリケーションはアニメーション マネージャーに現在の時刻を指定する必要があります。 アニメーション マネージャーが状態を更新し、すべてのアニメーション変数を適切な補間値に設定するように指示する場合も、現在の時刻が必要です。

概要

Windows アニメーションでサポートされる構成には、アプリケーション駆動型アニメーションとタイマー駆動型アニメーションの 2 つがあります。

アプリケーション駆動型アニメーションをアプリケーションで使用するには、各フレームを描画する前にアニメーション マネージャーを更新し、適切なメカニズムを使用してアニメーションに十分な頻度でフレームを描画する必要があります。 アプリケーション駆動型アニメーションを使用するアプリケーションでは、任意のメカニズムを使用して現在の時刻を判断できますが、Windows アニメーション タイマー オブジェクトは、アニメーション マネージャーが受け入れる単位で正確な時刻を返します。 アニメーションが再生されていないときに不要な描画を回避するには、アニメーションがスケジュールされたときに再描画を開始し、再描画を中断できるかどうかを各フレームの後にチェックするマネージャー イベント ハンドラーも用意する必要があります。 詳細については、「 アプリケーション駆動型アニメーション」を参照してください。

アプリケーション駆動型構成では、アプリケーションは IUIAnimationManager::GetStatus メソッドを呼び出して、アニメーションが現在スケジュールされていることを確認し、フレームがスケジュールされている場合は引き続きフレームを描画することを確認できます。 アニメーションがスケジュールされていない場合は再描画が停止するため、次回アニメーションがスケジュールされたときに再起動する必要があります。 アプリケーションは、アニメーション マネージャーの状態がアイドル状態 (現在スケジュールされていないアニメーション) からビジー状態に変わるときに通知を受け取るマネージャー イベント ハンドラーを登録できます。

アプリケーションでタイマー駆動型アニメーションを使用するには、アニメーション マネージャーをアニメーション タイマーに接続し、タイマー イベント ハンドラーを提供する必要があります。 アニメーション マネージャーがタイマーに接続されている場合、タイマーは、時間の経過に応じてアニメーションの状態を更新するタイミングをマネージャーに通知できます。 アプリケーションでは、タイマー ティックごとにフレームを描画する必要があります。 アニメーション マネージャーは、再生中のアニメーションがある場合にタイマーを通知できるため、再描画が不要なアイドル期間中にタイマーがオフになる可能性があります。 アニメーションが再生されていないときに不要な描画を回避するには、自動的に無効にするようにタイマーを構成する必要があります。 詳細については、「 タイマー駆動型アニメーション」を参照してください。

コード例

アニメーションのApplication-Driven

次のコード例は、Windows アニメーションサンプル アプリケーション駆動型アニメーショングリッド レイアウトから 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 アニメーション サンプル アプリケーション駆動型アニメーションから 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();
}

マネージャー イベント ハンドラーはメイン ウィンドウ オブジェクトへの参照を保持するため、マネージャー イベント ハンドラーをクリアするか (SetManagerEventHandlerNULL を渡すことによって)、メイン ウィンドウが破棄される前にアニメーション マネージャーを完全に解放する必要があります。

次のコード例は、Windows アニメーション のサンプル アプリケーション駆動型アニメーションの 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 アニメーション のサンプル アプリケーション 駆動型アニメーショングリッド レイアウトから MainWindow.cpp から取得されています。CMainWindow::OnPaint メソッドを参照してください。 アプリケーションは、モニターの更新レート (Direct2D とその既定の設定など) に自動的に同期するグラフィックス API を使用していることを前提としています。この場合、 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 から取得したものです。 このコード例では、タイマー イベント ハンドラーを定義します。これにより、ウィンドウのクライアント領域が無効になり、アニメーション状態が更新されるたびに再描画が行われます。

#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 アニメーションサンプル のタイマー駆動型アニメーションから MainWindow.cpp から取得されています。CMainWindow::InitializeAnimation を参照してください。 この例では、 CreateInstance メソッドを使用してタイマー イベント ハンドラーのインスタンスを作成し、 IUIAnimationTimer::SetTimerEventHandler メソッドを使用してタイマーに渡します。 タイマー イベント ハンドラーはメイン ウィンドウ オブジェクトへの参照を保持するため、タイマー イベント ハンドラーをクリアするか (SetTimerEventHandlerNULL を渡すことによって)、またはメイン ウィンドウが破棄される前に完全に解放されるタイマーをクリアする必要があります。

// 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 アニメーション のサンプル タイマー駆動型アニメーションの MainWindow.cpp から取得されています。CMainWindow::InitializeAnimation メソッドを参照してください。 アニメーション マネージャー オブジェクトの QueryInterface メソッドを呼び出して IUIAnimationTimerUpdateHandler へのポインターを取得し、IUIAnimationTimer::SetTimerUpdateHandler メソッドを使用してタイマーの更新ハンドラーとしてアニメーション マネージャーを設定することで、UIAnimationManager オブジェクトと UIAnimationTimer オブジェクトを接続します。 この接続を明示的にクリアする必要はありません。アプリケーションがアニメーション マネージャーとアニメーション タイマーの両方を解放した後、接続は安全にクリアされます。

// 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 アニメーションの概要