GIF mäßige Animationen in GUIs einbauen
Verfasst: 20.10.2006 10:32
Hallo!
In meinem Projekt soll das Logo des Programmes oben rechts in der Ecke in einem ImageGadget() angezeigt werden. Erst, wenn das Programm stark arbeitet und z. B. die Festplatte rekursiv durchgeht, soll dieses Standbild anfangen, sich zu verändern. Die Lösung, die ich erarbeitet habe, lässt die Animation genauso aussehen, als sei es ein echtes GIF Bild, obwohl nur hintereinander Einzelbilder abgespielt werden.
Nachteil: Keine Tranzparenz wie bei GIF (es sei denn, man nimmt ICOs)
Vorteile: Jedes Bildformat verwendbar (BMP, ICO, PNG, JPG, TIFF), das bedeutet: Nicht 256 Farben (GIF), sondern 24 Bit Farben!. Außerdem lässt sich, wenn man meinen Code nur geringfügig umbaut, die Wartezeiten bis zum nächsten Bild für jeden Frame der Animation individuell bestimmen. Die Animation ist jederzeit start- und stoppbar.
Was man braucht: 1 ImageGadget, 1 Thread, 1 Mutex Object und die einzelnen Bilder (Frames)
Zur Vorgehensweise: Ich habe alle Frames in einem PAK-Archiv (PB-PackerBefehle) in der Reihenfolge gespeichert, in der sie angezeigt werden.
Ich hoffe, der Code ist so klar geworden. Wenn die Animation abgespielt werden soll, muss der Hauptthread den Mutex entsperren (freigeben). Somit kriegt der Thread den Mutex, weil er ja ständig darauf wartet. Wenn der Mutex freigegeben wird, lasse ich mein Programm arbeiten (erinnert euch: Ich wollte, dass bei mir die Animation nur dann startet, wenn mein Programm irgendeine Aufgabe ausführen soll). Wenn mein Programm dann fertig ist it arbeiten, locked er wieder den Mutex. Das geht, weil der Thread nach jedem Durchlauf den Mutex wieder entsperrt und zu Beginn der Animation wieder zu sperren versucht.
Der Vorteil: Man kann so gezielt steuern, ob die Animation laufen soll oder nicht. Wenn die Animation stoppen soll, wird dank der ersten zwei Zeilen nach dem Repeat ja immer wieder das erste Bild angezeigt, somit erhält man keine komischen Ergebnisse.
Ich hoffe, der Code bzw. die Idee, die dahinter steckt, hat euch gefallen.
In meinem Projekt soll das Logo des Programmes oben rechts in der Ecke in einem ImageGadget() angezeigt werden. Erst, wenn das Programm stark arbeitet und z. B. die Festplatte rekursiv durchgeht, soll dieses Standbild anfangen, sich zu verändern. Die Lösung, die ich erarbeitet habe, lässt die Animation genauso aussehen, als sei es ein echtes GIF Bild, obwohl nur hintereinander Einzelbilder abgespielt werden.
Nachteil: Keine Tranzparenz wie bei GIF (es sei denn, man nimmt ICOs)
Vorteile: Jedes Bildformat verwendbar (BMP, ICO, PNG, JPG, TIFF), das bedeutet: Nicht 256 Farben (GIF), sondern 24 Bit Farben!. Außerdem lässt sich, wenn man meinen Code nur geringfügig umbaut, die Wartezeiten bis zum nächsten Bild für jeden Frame der Animation individuell bestimmen. Die Animation ist jederzeit start- und stoppbar.
Was man braucht: 1 ImageGadget, 1 Thread, 1 Mutex Object und die einzelnen Bilder (Frames)
Zur Vorgehensweise: Ich habe alle Frames in einem PAK-Archiv (PB-PackerBefehle) in der Reihenfolge gespeichert, in der sie angezeigt werden.
Code: Alles auswählen
; Das Mutex muss im Hauptprogramm und im Thread genutzt werden können, daher Global
Global logo=CreateMutex()
; Der Thread
Procedure animiertes_logo(temp)
; In dieser protected LinkedList werden die einzelnen Frames entpackt
; und deren ImageID()'s alle gespeichert.
; In meinem Projekt habe ich 6 Frames, also 6 Bilder im PAK-Archiv
Protected NewList logo_bilder.l()
AddElement(logo_bilder()) : logo_bilder()=ImageID(CatchImage(#PB_Any, NextPackFile()))
AddElement(logo_bilder()) : logo_bilder()=ImageID(CatchImage(#PB_Any, NextPackFile()))
AddElement(logo_bilder()) : logo_bilder()=ImageID(CatchImage(#PB_Any, NextPackFile()))
AddElement(logo_bilder()) : logo_bilder()=ImageID(CatchImage(#PB_Any, NextPackFile()))
AddElement(logo_bilder()) : logo_bilder()=ImageID(CatchImage(#PB_Any, NextPackFile()))
AddElement(logo_bilder()) : logo_bilder()=ImageID(CatchImage(#PB_Any, NextPackFile()))
; Diese Schleife muss ForEver ausgeführt werden
Repeat
; Zeige den 1. FRame an, wenn Animation nicht abgespielt werden soll
FirstElement(logo_bilder())
SetGadgetState(#logo, logo_bilder())
; Die Animation wird fortwährend abgespielt, wenn der Thread sich das
; Mutex ergattern kann
LockMutex(logo)
; Spiele einmal alle Frames durch (bei mir sind's 6 Einzelbilder (Frames))
ResetList(logo_bilder())
While NextElement(logo_bilder())
SetGadgetState(#logo, logo_bilder())
; Wenn man den Code an dieser Stelle erweitert, kann man
; die Anzeigedauer für jedes Bild selbst bestimmen. Ich brauche
; für meine 6 Frames abder nur 125 ms für jeden Frame
Delay(125)
Wend
; Mutex wird entsperrt, damit der Hauptthread bei Bedarf sich das Mutex ergattern
; und somit die Animation stoppen kann.
UnlockMutex(logo)
ForEver
EndProcedure
; Öffnen des PAK-Archivs und starten des Threads
If OpenPack("logo.pak")
; Mutex locken, damit die Animation nicht sofort beginnt.
LockMutex(logo)
; Wenn Thread gestartet werden, kann, setze seine Priorität etwas niedriger
; damit er nicht allzuviel die CPU auslastet (kann weggelassen werden)
Define logo_thread=CreateThread(@animiertes_logo(), 0)
If logo_thread
ThreadPriority(logo_thread, 15)
Else
; Wenn Thread nicht gestartet werden kann, dann zeige im ImageGadget
; das erste Bild an
SetGadgetState(#logo, ImageID(CatchImage(#PB_Any, NextPackFile())))
EndIf
Else
MessageRequester("Datei nicht gefunden", "Die Datei 'logo.pak' konnte nicht gefunden werden."+#CRLF$+"Programm wird beendet.", #MB_ICONERROR)
End
EndIf
Der Vorteil: Man kann so gezielt steuern, ob die Animation laufen soll oder nicht. Wenn die Animation stoppen soll, wird dank der ersten zwei Zeilen nach dem Repeat ja immer wieder das erste Bild angezeigt, somit erhält man keine komischen Ergebnisse.
Ich hoffe, der Code bzw. die Idee, die dahinter steckt, hat euch gefallen.
