Entwickler-Ecke

Multimedia / Grafik - Animation mit TTimer oder Schleife Verzögern?


boboy162 - Do 10.06.10 12:59
Titel: Animation mit TTimer oder Schleife Verzögern?
Hallo zusammen

Ich stehe grad vor einem Problem und hoffe dass ihr mir helfen könnt.
Ich hoffe ihr kennt alle das Galtonbrett?
(Mann hauen ein par Nägel an die Wand, aber nicht irgendwie sondern ganz oben in die 1.Reihe ein Nagel dann in die 2.Reihe drunter 2 Nägel und soweiter.Es ensteht eine Pyramide aus Nägeln. Dann kann man oben eine Kugel fallen lassen und die sucht sich dann ihren Weg durch die Nägel. )


Der Code der den Weg berechnet den die Kugel nimmt, steht schon ich bin jetzt dafür zuständig eine Animation draus zumachen bei der die Kugel sichtbar ist.

Fraqe: Ich hab versucht eine Animation mit dem TTimer Objekt auf die Reihe zukriegen.Leider bin ich auf das Problem gestoßen das diese Prozedur erst ganz am Ende nach dem alle anderen Prozeduren abgelaufen wurden sind ausgeführt wird.

-->Kann man dies irgendwie regel, bzw. kann man auf die Prozedur Timer1.Timer direkt zugreifen.


Wenn nicht -->Ich könnte mir das auch mit einer Verzögerung in einer For Schleife auch vorstellen.
Wie funktuniert das ungefähr?


VIELEN DANK


GRUß


Moderiert von user profile iconNarses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Do 10.06.2010 um 15:01


ffgorcky - Do 10.06.10 14:41

Also ich habe damit zwar noch keine Erfahrung, aber ich würde das ganze einfach mal mit sleep versuchen, wie es zum Beispiel auch der Thread-Starter in diesem Thread [http://www.delphi-forum.de/viewtopic.php?t=99278&highlight=sleep] gemacht hat.


Bergmann89 - Do 10.06.10 17:19

Hey,

sleep is bei sowas ganz böse, weil sich dann die ganze anwendung aufhängt, der Timer was rshcon die richtige lösung. bei nem INtervall von 10-50ms sieht die Bewegung auch relativ flüssig aus. Du hast 2 möglichkeiten, entweder du berechnest dir am anfang den Weg der Kugel (evtl. pixelgenau zur besseren Darstellung) und lässt die Kugel dann einfach mit dem Timer den weg abschreiten, oder du berechnest es in echtzeit, das heißt du musst die die neue Position der Kugel in anhängigkeit der Zeit un der neuen Position berechnen. Ich weiß nicht in wieweit das deine Berechnungsprozedur zulässt, un wieviel du da umschreibenmusst, aber das sind die 2 Wege, die mir jetzt auf anhiebt einfallen...

MfG Bergmann


delfiphan - Fr 11.06.10 17:58

Du könntest einen Worker-Thread nehmen, dort den nächsten Schritt berechnen, ggf. warten, und mit Synchronize im MainThread die Grafik updaten.


boboy162 - Sa 12.06.10 18:45

Ahhhh dass hört sich genau so an wie ich es gerne hätte.

Was ist aber eigentlich ein Worker-Thread? und dass Synchronize?

Google hat dazu nicht grad viel ausgespuckt.


Vielen Dank


Gruß


Bergmann89 - Sa 12.06.10 19:04

Hey,

der Worker-Thread is einfach ein Thread, der die Berechnungen passend zu deiner Animation ausführt, da kannst du dann mit Sleep arbeiten, weil dann nur der Thread hängen bleibt, du die Anwendung aber normal benutzen kannst. Synchronize dinet zum Aufrufen von Methoden aus einem Thread heraus. Methoden, die mit Synchronize aufgerufen wurden, werden IMMER im Kontext des Main-Threads ausgeführt. Sowas benutzt man, wenn man Events an den Main-Thread schicken will. (Das steht aber glaube auch in der Delpi Hilfe)

MfG Bergmann.


delfiphan - Sa 12.06.10 19:11

Sowas wie im Anhang.


Bergmann89 - Sa 12.06.10 19:17

Hey,

wenn du dir die Mühe machst un die ArbeitsForm an den Thread übergibst solltest du diese dann vlt auch im Thread benutzen ;)

Delphi-Quelltext
1:
2:
3:
4:
procedure TWorkerThread.Draw;
begin
  FForm1.Button1.SetBounds(FPosition.X, FPosition.Y, 5050);
end;


MfG Bergmann.


delfiphan - Sa 12.06.10 19:27

Nein, ich habe ein Property Form1 gemacht, das den Thread überprüft, weil das sonst die nächste Frage ist, wieso es manchmal nicht funktioniert.


Bergmann89 - Sa 12.06.10 19:41

Okay, ich nehm alles zurück, die Property hab ich übersehen, sry :oops:


boboy162 - So 13.06.10 02:04

hmmmm...hört sich bisher für mich bissle Komplex an... naja mir würds eigentlich auch reichen wenn das Programm sich während der Schleife beenden liese. Weil irgendwie blockiert dieses "Sleep" alles.

Gibts irgendie eine alternative Möglichkeit zum "Worker-Thread" um das laufenden Programm (also es befindet sich in einer Schleife mit "Sleep()") komplett zubeenden?

Also ButtenClick Ereignis mit "close;" Befehl funktuniert nicht...soweit bin ich.


Vielen Dank schonmal

Gruß


Delete - So 13.06.10 02:28

Nicht das Sleep blockiert alles, sondern weil du in jeden Schleifendurchlauf Synchronize aufrufst, womit der Code dann wieder im Kontext des Hauptthreads mit deinem Fenster ausgeführt wird.



user profile iconboboy162 hat folgendes geschrieben Zum zitierten Posting springen:
Ich hab versucht eine Animation mit dem TTimer Objekt auf die Reihe zukriegen.Leider bin ich auf das Problem gestoßen das diese Prozedur erst ganz am Ende nach dem alle anderen Prozeduren abgelaufen wurden sind ausgeführt wird.

Welche Prozedur wird nach allen anderen Prozeduren ausgeführt? Das Timer Ereignis sollte immer nach dem angegebenen Intervall aufgerufen werden.


Bergmann89 - So 13.06.10 06:54

Hey,

ich glaub er hat noch gar keine Threads benutzt. Er redet noch von der normalen Anwendung. Wenn du nach dem sleep ein ProgressMessages setzt sollte es möglich sein, den Abbrechen Button zu drücken, aber wirklich ellegant ist die Lösung nich, im Gegenteil!
Und soweit ich das verstanden hab wird die Prozedur, die den Weg berechnet vor der Timer-Prozedur ausgeführt. Deshalb muss man die RechenProzedur auch von der Zeit abhängig machen un dann jedesmal im Timer-Event aufrufen.

MfG Bergmann


jaenicke - So 13.06.10 08:18

user profile iconboboy162 hat folgendes geschrieben Zum zitierten Posting springen:
Fraqe: Ich hab versucht eine Animation mit dem TTimer Objekt auf die Reihe zukriegen.Leider bin ich auf das Problem gestoßen das diese Prozedur erst ganz am Ende nach dem alle anderen Prozeduren abgelaufen wurden sind ausgeführt wird.
Das hört sich so an als hättest du das Konzept von TTimer falsch verstanden. In jedem Timer-Event musst du einen Schritt machen. Nach dem abgelaufenen Intervall, z.B. 500 Millisekunden, wird dann das nächste Mal das Timer-Event aufgerufen. Dann kommt der nächste Schritt.

Wenn du in dem Timer-Event eine Schleife und Sleep benutzt, dann kannst du dir das komplett sparen. Das hat dann nichts mit einem Timer zu tun.


boboy162 - So 13.06.10 19:45

ok mir ist schon klar dass das besser ist wenn ich den TTimer benutze.
Nur das ganze lief so ab, dass ich und ein Freund ein Projekt vorgeschrieben bekommen haben. Den ganzen Teil der den Weg berechnet etc. hat er gemacht, und ich soll dazu die Grafik Animieren.

Naja da man das Programm nach der Animation beenden kann denke ich reicht das, weil wenn ich jetzt den TTimer benutzten wollte dann müsste ich zuviel umschreiben.

Aber gibt es wirklich keinen Weg das Programm während der Schleife (mit sleep) dass Programm zubeenden. Ich bin für alle Lösungen offen. Sonst geb ich mich nun auch so zufrieden.


Vielen Dank


Gruß


jaenicke - So 13.06.10 19:57

Dann musst du das in der Schleife auch einbauen, dass du bei OnCloseQuery nen Flag setzt, damit die Schleife beendet wird. Außerdem würde ich eher Delay [http://www.delphipraxis.net/topic7355_delay+revisited.html] benutzen, damit die Oberfläche noch nutzbar bleibt.


delfiphan - So 13.06.10 20:46

Angenommen, du möchtest deine Schleife nicht auseinanderreissen und stückweise ausführen (da dir das zu aufwändig ist) hast du folgende Möglichkeiten:

1. Führe die Schleife in einem Thread aus und zeichne synchronisiert im MainThread (Beispiel oben)

2. Du verwendest Sleep oder Delay wie oben erwähnt. Das Problem hier ist, dass es Code braucht, der wie die Hauptschleife Windows-Messages dispatcht (bei Delay ist das bereits eingebaut). Du solltest nach jeder dispatchten Message auf Application.Terminated und den ModalResult der Form überprüfen und ggf. die Schleife verlassen. OnCloseQuery finde ich ist jetzt weniger geeignet dafür.

3. Du berechnest die Positionen vor und zeichnest die Kugel dann mit einem Timer.

4. Du verwendest Continuation und einen Timer. Den sequentiellen Code mit der Schleife führst du dann stückweise im Timer aus (Beispiel im Anhang).

Mehr fällt mir jetzt nicht ein...


boboy162 - Mo 14.06.10 12:08

Danke für die Zusammenfassung...so gefällts mir wenn alles auf den Punkt gebracht wird :)

Ich werd dann mal die einzelnen Lösungen nochmal überdenken und dann die geeignetste umsetzten.


Danke


Gruß