Aktualisieren des Animations-Managers und Zeichnen von Frames

Jedes Mal, wenn eine Anwendung ein Storyboard plant, muss die Anwendung die aktuelle Zeit für den Animations-Manager bereitstellen. Die aktuelle Zeit ist auch erforderlich, wenn sie den Animations-Manager anweisen, seinen Zustand zu aktualisieren und alle Animationsvariablen auf die entsprechenden interpolierten Werte festzulegen.

Übersicht

Von der Windows-Animation werden zwei Konfigurationen unterstützt: anwendungsgesteuerte Animation und timergesteuerte Animation.

Um anwendungsgesteuerte Animationen in Ihrer Anwendung verwenden zu können, müssen Sie den Animations-Manager aktualisieren, bevor Sie jeden Frame zeichnen, und einen geeigneten Mechanismus verwenden, um Frames häufig genug für die Animation zu zeichnen. Eine Anwendung, die anwendungsgesteuerte Animation verwendet, kann einen beliebigen Mechanismus verwenden, um die aktuelle Zeit zu bestimmen, aber das Windows Animation-Timerobjekt gibt eine genaue Zeit in den vom Animations-Manager akzeptierten Einheiten zurück. Um unnötiges Zeichnen zu vermeiden, wenn keine Animationen wiedergegeben werden, sollten Sie auch einen Manager-Ereignishandler bereitstellen, um das Neuzeichnen bei geplanten Animationen zu starten und nach jedem Frame zu überprüfen, ob das Neuzeichnen angehalten werden kann. Weitere Informationen finden Sie unter Anwendungsgesteuerte Animation.

In der anwendungsgesteuerten Konfiguration kann eine Anwendung die IUIAnimationManager::GetStatus-Methode aufrufen, um zu überprüfen, ob Animationen derzeit geplant sind, und weiterhin Frames zeichnen, falls sie derEn sind. Da das Neuzeichnen beendet wird, wenn keine Animationen geplant sind, muss sie beim nächsten Geplanten neu gestartet werden. Eine Anwendung kann einen Manager-Ereignishandler registrieren, um benachrichtigt zu werden, wenn sich die status des Animations-Managers vom Leerlauf (derzeit sind keine Animationen geplant) in ausgelastet ändert.

Um timergesteuerte Animation in Ihrer Anwendung zu verwenden, müssen Sie den Animations-Manager mit einem Animationstimer verbinden und einen Timerereignishandler bereitstellen. Wenn der Animations-Manager mit einem Timer verbunden ist, kann der Timer dem Manager mitteilen, wann der Animationszustand im Laufe der Zeit aktualisiert werden soll. Die Anwendung sollte einen Rahmen für jeden Timer-Tick zeichnen. Der Animations-Manager kann dem Timer wiederum mitteilen, wenn Animationen wiedergegeben werden, sodass sich der Timer im Leerlauf abschalten kann, wenn das Neuzeichnen unnötig ist. Um unnötiges Zeichnen zu vermeiden, wenn keine Animationen wiedergegeben werden, sollten Sie den Timer so konfigurieren, dass er sich automatisch deaktiviert. Weitere Informationen finden Sie unter Timer-Driven Animation.

Beispielcode

Application-Driven Animation

Der folgende Beispielcode stammt aus "ManagerEventHandler.h" aus den Beispielen "Anwendungsgesteuerte Animation" und "Rasterlayout" von Windows-Animation. Er definiert den Manager-Ereignishandler.

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

    ...

};

Der folgende Beispielcode stammt aus "MainWindow.cpp" aus dem Anwendungsgesteuerten Animation-Beispiel für Windows-Animation. Siehe CMainWindow::InitializeAnimation. In diesem Beispiel wird eine instance des Manager-Ereignishandlers mithilfe der CreateInstance-Methode erstellt und mit der IUIAnimationManager::SetManagerEventHandler-Methode an den Animations-Manager übergeben.

// 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();
}

Da der Manager-Ereignishandler einen Verweis auf das Standard Fensterobjekt behält, sollte der Manager-Ereignishandler gelöscht werden (indem NULL an SetManagerEventHandler übergeben wird), oder der Animations-Manager sollte vollständig freigegeben werden, bevor das Standard Fensters zerstört wird.

Der folgende Beispielcode stammt aus "MainWindow.cpp" im Beispiel für die anwendungsgesteuerte Animation von Windows-Animation. Siehe die CMainWindow::OnPaint-Methode. Sie ruft die IUIAnimationManager::GetTime-Methode auf, um die Zeit in den Einheiten abzurufen, die für die IUIAnimationManager::Update-Methode erforderlich sind.

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

    ...

}

Der folgende Beispielcode stammt aus "MainWindow.cpp" aus den Windows-Animationsbeispielen Anwendungsgesteuerte Animation und Rasterlayout. Siehe die CMainWindow::OnPaint-Methode. Es wird davon ausgegangen, dass die Anwendung eine Grafik-API verwendet, die automatisch mit der Aktualisierungsrate des Monitors synchronisiert wird (z. B. Direct2D mit den Standardeinstellungen). In diesem Fall reicht ein Aufruf der InvalidateRect-Funktion aus, um sicherzustellen, dass der Malcode beim Zeichnen des nächsten Frames erneut aufgerufen wird. Anstatt InvalidateRect bedingungslos aufzurufen, empfiehlt es sich, zu überprüfen, ob noch Animationen mit GetStatus geplant sind.

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

Der folgende Beispielcode stammt aus TimerEventHandler.h aus dem Windows-Animationsbeispiel timergesteuerte Animation. Der Beispielcode definiert den Timerereignishandler, der den Clientbereich des Fensters ungültig macht, um nach jeder Aktualisierung des Animationszustands eine Neubemalung zu verursachen.

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

    ...

};

Der folgende Beispielcode stammt aus "MainWindow.cpp" aus dem Windows-Animationsbeispiel timergesteuerte Animation. Siehe CMainWindow::InitializeAnimation. In diesem Beispiel wird eine instance des Timerereignishandlers mithilfe der CreateInstance-Methode erstellt und mit der IUIAnimationTimer::SetTimerEventHandler-Methode an den Timer übergeben. Da der Timerereignishandler einen Verweis auf das Standard-Fensterobjekt behält, sollte der Timerereignishandler gelöscht (durch Übergeben von NULL an SetTimerEventHandler) oder der Timer vollständig freigegeben werden, bevor das Standard Fensters zerstört wird.

// Create and set the timer event handler

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

Der folgende Beispielcode stammt aus MainWindow.cpp im Windows-Animationsbeispiel timergesteuerte Animation. Siehe die CMainWindow::InitializeAnimation-Methode. Es ruft die QueryInterface-Methode für das Animations-Manager-Objekt auf, um einen Zeiger auf IUIAnimationTimerUpdateHandler zu erhalten, und verbindet dann die UIAnimationManager- und UIAnimationTimer-Objekte, indem der Animations-Manager als Updatehandler des Timers mithilfe der IUIAnimationTimer::SetTimerUpdateHandler-Methode festgelegt wird. Beachten Sie, dass es nicht erforderlich ist, diese Verbindung explizit zu löschen. die Verbindung wird sicher gelöscht, nachdem die Anwendung sowohl den Animations-Manager als auch den Animationstimer freigegeben hat.

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

        ...

    }
}

Wenn UI_ANIMATION_IDLE_BEHAVIOR_DISABLE nicht verwendet wird, muss auch der Timer aktiviert werden, um das Ticken zu starten.

Vorheriger Schritt

Bevor Sie mit diesem Schritt beginnen, sollten Sie diesen Schritt abgeschlossen haben: Erstellen von Animationsvariablen.

Nächster Schritt

Nach Abschluss dieses Schritts ist der nächste Schritt: Lesen der Werte der Animationsvariablen.

IUIAnimationManager::GetStatus

IUIAnimationManager::SetManagerEventHandler

IUIAnimationManager::Update

IUIAnimationTimer::GetTime

IUIAnimationTimer::SetTimerUpdateHandler

UIAnimationManager

UIAnimationTimer

Übersicht über Windows-Animationen