Mit ‘SWT’ getaggte Artikel

Animationen mit SWT

Mittwoch, 07. Oktober 2009

In SWT(JFace) gibt es momentan keine Hilfestellung bei der Erstellung von Animationen. Selbst die Darstellung von animierten GIF-Bildernist etwas umständlich (Beispiel). Eclipse 4 wird voraussichtlich eine eigene API für Animationen mitbringen, bis dahin lohnt ein Blick auf das SWT Animation Toolkit von Nicolas Richeton, dass Zugang zum Nebula Projekt gefunden hat.

Es bringt eine Reihe von Effekten mit, wie zum Beispiel SmooothScrolling, Animierte Größenänderung und Bewegung von SWT-Controls sowie Ein- und Ausblenden von Fenstern. Allerdings keine Animationen für Bilder (SWT-Image). Folgend nun eine Erweiterung dieser Effekte um eine Pulsieren-Animation eines Icons. Die Transparenz des Bildes wird stufenweise verringert (und wieder erhöht). Folgend die Methode zum Erzeugen der Einzelbilder für die Animation:

private Image[] createImageArray(final Image origImage) {
    Image[] images = new Image[10];
    Image previous = origImage;
    for (int i = 0; i < images.length; i++) {
        ImageData data = previous.getImageData();
 
        int[] lineData = new int[data.width];
        for (int y = 0; y < data.height; y++) {
            data.getPixels(0, y, data.width, lineData, 0);
            // Analyze each pixel value in the line
            for (int x = 0; x < lineData.length; x++) {
                int pixelValue = lineData[x];
                if (pixelValue == data.transparentPixel) {
                    continue;
                }
                int alpha = data.getAlpha(x, y) - i * 25;
                if (alpha < 0) {
                    alpha = 0;
                } else if (alpha > 255) {
                    alpha = 255;
                }
                data.setAlpha(x, y, alpha);
            }
        }
        images[i] = new Image(Display.getCurrent(), data);
        previous = images[i];
    }
    return images;
}

Es muss für jedes Einzelbild die Transparenz aller Pixel verändert werden, da SWT keinen passenden vordefinierten Filter mitbringt. Hat man die Einzelbilder der Animation erstellt, müssen diese nur noch zum richtigen Zeitpunkt dargestellt werden. Folgend die Klasse Pulse die von AbstractEffect, eine Klasse aus dem Animation Toolkit, erbt:

public class Pulse extends AbstractEffect {
 
    private final RestoreImage restoreImage = new RestoreImage();
    private final ImageButton imageButton;
    private final Image origImage;
    private final Image[] images;
 
    public Pulse(final ImageButton imageButton, final long lengthMilli) {
        super(lengthMilli, new LinearInOut(), null, null);
        origImage = imageButton.getImage();
        this.imageButton = imageButton;
        images = createImageArray(origImage);
 
        easingFunction.init(0, 1, (int) lengthMilli);
    }
 
    @Override
    public void applyEffect(final long currentTime) {
        double value = easingFunction.getValue((int) currentTime);
 
        int img = 0;
        if (value < 0.5) {
            img = Math.min((int) (value * 20), 9);
        } else {
            img = Math.min((int) (10 - (value * 20 - 10)), 9);
        }
 
        if (!imageButton.isDisposed()) {
            imageButton.updateImage(images[img]);
        }
    }
}

Das ganze kann wie folgt gestartet werden:

AnimationRunner runner = new AnimationRunner(10);
runner.runEffect(new Pulse(imageButton, 1000));

Die Animation wird nun mit 10 Bildern pro Sekunde (fps) ausgeführt. Die Methode applyEffect wird dabei 10 mal ausgeführt: 10fps * 1000ms. Mögliche Verbesserungen:

  • Die Anzahl der erzeugten SWT-Images automatisch an die fps anpassen.
  • Das aktuelle Bild der Animation durch eine Sinus-Funktion bestimmen. Durch ein Erhöhen der Frequenz kann das Pulsieren mehrfach innerhalb eines Aufrufes ausgeführt werden.
  • Die erzeugten Resourcen (SWT-Images) müssen am Ende wieder freigegeben werden (dispose()) werden: runnableOnStop und runnableOnCancel der Oberklasse verwenden.

Jan Kuenstler