Scrollende Animationen erstellen

Einleitung

Microsoft Visual Basic bietet keine einfachen Möglichkeiten, Text und Grafik zu scrollen, um damit eine einfache Animation zu erstellen. Diese Form von Animationen ist interessant für folgende Zwecke:

Es wäre möglich, ein Label-Steuerelement mit transparentem Hintergrund, das den zu scrollenden Text enthält, mit einem Timer über eine Hintergrundgrafik zu bewegen, allerdings tritt bei dieser Methode ein unschönes Flackern des Label-Steuerelements auf. Derselbe Effekt ist auch bei der Verwendung des Image-Steuerelement zu bemerken, das eine transparente Grafik enthalten kann. Daher muß man eine Lösung über das Windows-API suchen.

Ein einfaches Beispiel

Eine gute Möglichkeit bieten die Funktionen aus der GDI-Schnittstelle des Systems. Diese API-Funktionen sind unter 32-Bit-Windows in der gdi32.dll implementiert, seit Windows 98 bzw. Windows 2000 stellt das System auch die msimg32.dll zur Verfügung, die als Ergänzung zur gdi32.dll gedacht ist. So war es beispielsweise mit herkömmlichen GDI-API-Funktionen nur schwer möglich, transparente Grafiken auf einen Gerätekontext zu blitten. Dazu wird von der msimg32.dll die Funktion TransparentBlt zur Verfügung gestellt; zudem finden sich in dieser DLL z. B. auch Funktionen zum Zeichnen von Farbverläufen und zum Überblenden zweier Gerätekontexte.

Wie oben beschrieben, wäre es möglich, die TransparentBlt API-Funktion aus der msimg32.dll zu verwenden, um den transparenten Text in einer Grafik über den Hintergrund zu blitten. Das Problem dabei ist, daß diese Funktion nur auf neueren Betriebssystemversionen vorhanden ist und daher separater Code für frühere Versionen geschrieben werden müßte (inklusive eines Versionsüberprüfungen). Das Mitausliefern der msimg32.dll ist aus lizenzrechtlichen Gründen problematisch.

Die Prozedur TransBlt

Aus oben genannten Gründen wollen wir eine eigene Prozedur entwickeln, die eine Grafik transparent über eine andere legen kann. Die Implementierung der Prozedur TransBlt stützt sich auf die API-Funktion BitBlt aus der gdi32.dll. Diese Prozedur maskiert die Vordergrundbitmap in einem Speichergerätekontext (ein Gerätekontext, der nicht angezeigt wird, sondern nur im Arbeitsspeicher angelegt wird, um eine Bitmap zu speichern bzw. Grafikoperationen auf diesen Gerätekontext anzuwenden). Wenn Grafikoperationen auf einen Speichergerätekontext angewendet werden, sind diese etwas schneller als wenn sie auf einen sichtbaren Gerätekontext angewendet werden würden) und erstellt dann eine transparente Bitmap, die anschließend über den Ziel-Gerätekontext geblittet wird.

Die folgende Abbildung zeigt das fertige Programm, wobei der Text als Grafik gespeichert ist und mit der Prozedur TransBlt über den „Sternenhimmel“ gezeichnet wird:

[Illustration] Startansicht des beschriebenen Scrollers

Startansicht des beschriebenen Scrollers.

Damit diese Funktion (wie auch die anderen GDI-Funktionen) funktioniert, muß die ScaleMode-Eigenschaft von Quell- und Zielobjekt auf vbPixels eingestellt und die AutoRedraw-Eigenschaft auf True gesetzt werden. Folgendes Listing zeigt den Prozedurkopf von TransBlt. Wie an den Parametern erkennbar ist, unterscheidet sich diese Prozedur von der API-Funktion TransparentBlt nur dadurch, daß die Breite und Höhe auf dem Quell-Gerätekontext nicht angegeben werden muß. Da es sich um eine Sub-Prozedur handelt, wird auch kein Wert zurückgegeben, der über den Erfolg des Funktionsaufrufs Aufschluß gibt:

Public Sub TransBlt( _
    ByVal hDestDC As Long, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal nWidth As Long, _
    ByVal nHeight As Long, _
    ByVal hSrcDC As Long, _
    ByVal xSrc As Long, _
    ByVal ySrc As Long, _
    ByVal lngTransColor As Long _
)
Kopf der Prozedur TransBlt.

Auf langsamen Rechnern ist die Verwendung eines Timer-Steuerement als Zeitgeber nicht nötig, da die TransBlt-Prozedur das System kurzzeitig „blockiert“ und dadurch die Anzeige verzögert. Außerdem wird bei jedem Schleifendurchlauf DoEvents aufgerufen, damit die Ereignisse des Formulars weiterhin abgearbeitet werden. Auf moderneren Rechnern ist es jedoch unumgänglich, das Neuzeichnen alle n Millisekunden durchzuführen, da sonst die Geschwindigkeit der Animation zu schnell sein kann. Nachstehendes Listing zeigt die Deklaration der API-Funktion TransparentBlt:

Private Declare Function TransparentBlt Lib "msimg32.dll" ( _
    ByVal hdcDest As Long, _
    ByVal nXOriginDest As Long, _
    ByVal nYOriginDest As Long, _
    ByVal nWidthDest As Long, _
    ByVal nHeightDest As Long, _
    ByVal hdcSrc As Long, _
    ByVal nXOriginSrc As Long, _
    ByVal nYOriginSrc As Long, _
    ByVal nWidthSrc As Long, _
    ByVal nHeightSrc As Long, _
    ByVal crTransparent As Long _
) As Long
Kopf der Funktion TransparentBlt.

Der Algorithmus

Im hier beschriebenen Beispiel wird ein Text mit Grafikelementen transparent von oben nach unten über eine Hintergrundgrafik bewegt. Die Hintergrundgrafik stellt einen Sternenhimmel dar, beim „Text“ handelt es sich um Informationen zu einer Anwendung. Der Text ist als Bitmap abgelegt, damit auch Grafikelemente angezeigt werden können:

[Illustration] Schematische Darstellung des Algorithmus

Schematische Darstellung des Algorithmus.

Bevor der transparente Vordergrund geblittet wird, wird der Inhalt der Ziel-PictureBox geleert und ein neuer Hintergrund geblittet. Dies ist einerseits notwendig, um die bereits vorhandene Anzeige zu löschen, andererseits wird in diesem Beispiel alle 40 Schleifendurchläufe (d. h., wenn die Vertikalposition auf der Quellbitmap um 40 Pixel nach unten verschoben wurde) das Hintergrundbild gewechselt, wodurch die Sterne am Himmel „flackern“. Obige Grafik stellt den verwendeten Algorithmus dar, bei dessen Ablauf zwischen folgenden 3 Fällen unterschieden werden kann:

Fall 1:

In diesem Fall wird der Teil der Grafik von der Vertikalposition 0 bis 0 plus die Höhe des Zielbereichs transparent auf den Gerätekontext der Ziel-PictureBox geblittet.

Fall 2:

Die Vertikalposition wird entlang des blauen Pfeils bei jedem Schleifendurchlauf inkrementiert, wodurch der aktuell geblittete Bereich auf der Quellbitmap nach unten wandert.

Fall 3:

Wird die Vertikalposition plus der Höhe des Zielbereichs größer als die Höhe des Quellbereichs, so muß zuerst der Bereich von der aktuellen Vertikalposition mit der Höhe, die sich aus der Gesamthöhe der Quellbitmap minus die aktuelle Vertikalposition ergibt geblittet werden und anschließend der Bereich von der Vertikalposition 0 bis mit der Höhe (aktuelle Position plus Höhe des Zielbereichs minus die Gesamthöhe der Quellbitmap) auf dem Zielobjekt an der Vertikalposition, die der Höhe des Bereichs, der zuerst geblittet wurde, entspricht.

Eine andere Sichtweise ist die Folgende: Die Grafik, die über den Hintergrund bewegt wird, ist ein Band, das sich dauernd in eine Richtung bewegt. Der Betrachter sieht dann nur einen Ausschnitt aus diesem Band. Die nächste Abbildung zeigt das Sichtfenster des Benutzers sowie das Band, das hier aus Gründen des leichteren Nachvollziehens auf Rollen geführt wird:

[Illustration] Alternative Sichtweise des Algorithmus

Die Quellbitmap wandert hinter dem aktuellen Sichtbereich nach oben.

Durch diesen Algorithmus wird nach dem Abspielen der gesamten Quellbitmap erneut die Quellbitmap abgespielt, was einem schleifenartigen Durchlauf gleicht. Dies ist in der vorigen Abbildung dargestellt. Folgende Grafiken zeigen das Anzeigeresultat zu den in der Skizze beschriebenen Zuständen, die Grafik am Seitenanfang zeigt ein Beispiel für Fall 1:

[Illustration] Anzeige im Fall 2

Anzeige im Fall 2.

Die obenstehende Abbildung zeigt ein Beispiel für den Fall, daß ein zusammenhängender Ausschnitt aus der Vordergrundbitmap zu sehen ist. Bei der nächsten Abbildung handelt es sich um ein Beispiel für Fall 3, da sowohl ein Stück vom oberen als auch dem unteren Ende der Vordergrundbitmap angezeigt werden:

[Illustration] Anzeige im Fall 3

Anzeige im Fall 3.

Um die Animation horizontal ablaufen zu lassen, müssen eine entsprechende Grafik erstellt und im Algorithmus x- und y-Koordinaten vertauscht werden.

Schlußwort

Das vorgestellte Beispiel entstand auf mehrere Anfragen, die an mich herangetragen wurden und ist prinzipiell an Programmiereinsteiger gerichtet. Um eine Grafik transparent über eine andere zu legen, müssen nicht unbedingt API-Funktionen verwendet werden, sondern dies kann auch über einige Umwege mit der Methode PaintPicture getan werden. Ferner sollte bedacht werden, daß sich ein gutes Programm nicht durch grafische Spielereien auszeichnet, sondern durch eine praktische Benutzerführung und möglichst breiter Unterstützung durch verschiedene Systeme. Selbst wenn mittlerweile die meisten Computerbenutzer über Hardware, die mehr als 256 Farben darstellen kann, verfügen, sollten auch jene Benutzer bedacht werden, bei denen dies nicht der Fall ist.

Downloads

Beispielprojekt (CreditsScroller.zip)

Projekt im Visual-Basic-6.0-Format.