Autor |
Beitrag |
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mo 25.07.16 20:54
Hallo!
Folgende for-Schleife:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| with ComputerPlayedCard do for i := ComputerLImage1.Left to iAbgelegtePosX-65 do begin SetBounds(i, iTalonPosY, Width, Height); if Application.Terminated then exit; Sleep(iDelay); if Odd(i) then Form1.Refresh; end; |
Ja, ich weiss, das gehört in einen TTimer... Aber der Code ist alt und ich zu bequem, alles aufzudröseln und umzuschreiben, da ist ja noch mehr Code ausserhalb der Schleife!
Sleep dient nur dazu, die Schleife einzubremsen, um die Grafik als bewegte Animation darzustellen: Die Spielkarte wandert über das Spielfeld.
Wenn nun Delphi läuft, bewegt sie sich flott dahin, und zwar auch dann, wenn das Projekt gar nicht geladen ist und ich mein Programm ausserhalb von Delphi starte. Es genügt, dass Delphi im Speicher ist!
Läuft Delphi nicht, ist die Bewegung wesentlich langsamer! -> Wenn Delphi läuft, verändert sich das Verhalten des Programms?!
Ich weiss, diese Lösung ist grauenhaft, aber es würde mich interessieren, warum das so ist!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Mi 27.07.16 07:49
Wenn man nach "Delay" googelt, findet man diversen Code dazu. Auch damit zeigt sich der Effekt.
Die blosse Anwesenheit von Delphi beeinflusst das Verhalten eines Programmes. Seltsam!
Ich habe mir überlegt, ob mit Delphi vielleicht eine dll geladen ist, die das bewirkt, oder ob es am Delphi-Debugger liegt. Was auch immer, ich habe keine Erklärung.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
GuaAck
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: Mi 27.07.16 20:12
Hallo,
mit folgenden Programm habe ich keinen Unterschied festgestellt:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| PROCEDURE TForm1.Button1Click(Sender: TObject); VAR i, j: integer; BEGIN
Edit1.Text := ''; application.ProcessMessages; FOR j := 0 TO 19 DO BEGIN FOR i := 1 TO 100 do sleep(10); Edit1.Text := Edit1.Text + 'X'; application.ProcessMessages; END; END; |
Bei sleep (1) geht es viel langsamer, nach meiner Erinnerung ist 10 ms die kleinste Zeiteinheit.
Vielleicht hängt es irgendwie mit dem zusammen, was in der Delphi-Hilfe bei Sleep steht:
Zitat: | Remarks
A thread can relinquish the remainder of its time slice by calling this function with a sleep time of zero milliseconds.
You have to be careful when using Sleep and DDE. If a thread creates any windows, it must process messages. DDE sends messages to all windows in the system. If you have a thread that uses a wait function with no time-out interval, the system will deadlock. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than Sleep.
|
Viele Grüße
GuaAck
|
|
OlafSt
Beiträge: 486
Erhaltene Danke: 99
Win7, Win81, Win10
Tokyo, VS2017
|
Verfasst: Do 28.07.16 14:06
IMHO schreit allein die Tatsache, das sich das Compilat anders verhält, nmehr als laut danach, es komplett zu überarbeiten...
_________________ Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 28.07.16 20:14
GuaAck hat folgendes geschrieben : | Bei sleep (1) geht es viel langsamer, nach meiner Erinnerung ist 10 ms die kleinste Zeiteinheit. |
Ich merke da keinen grossen Unterschied. Ausser, wenn Delphi läuft...
OlafSt hat folgendes geschrieben : | IMHO schreit allein die Tatsache, das sich das Compilat anders verhält, nmehr als laut danach, es komplett zu überarbeiten... |
Ich lasse den Code jetzt jeweils in eigenen Threads laufen (Komponente TJvThread von den JEDIs), und auch da brauche ich ein Sleep oder Delay, damit man die Animation sieht. Und auch da verhält sich alles wie beschrieben. Aber warum?
Den Umbau hätte ich mir sparen können.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
GuaAck
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: Fr 29.07.16 00:08
Setze doch mal die Priorität Deines Programms von "normal" auf "high". Ändert sich was?
Gruß GuaAck
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 29.07.16 07:04
In einem Thread kannst du ja ohnehin nicht auf GUI Elemente zugreifen ohne zu synchronisieren. Das wiederum kostet Zeit.
Das Stichwort hier ist timebased movement. Im Moment ist es eben Zufall wie lange deine Bewegung dauert, da es auf jedem Rechner und je nach Auslastung anders ist. Sinnvoller ist festzulegen, dass die Bewegung z.B. 200ms dauern soll. Dann brauchst du lediglich solange bis die 200ms erreicht sind in einer while-Schleife jeweils die Position anhand der vergangenen Zeit zu setzen.
Sprich wenn 50ms vergangen und du eine Strecke von 20 Pixeln startend bei 75 Pixeln bewegen willst, setzt du die Position entsprechend:
Left = OldLeft + (NewPos - OldLeft) * (CurrentTime - StartTime) / 200 = 75 + 20 * 50 / 200 = 80
Für diesen Beitrag haben gedankt: galagher
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 29.07.16 07:57
jaenicke hat folgendes geschrieben : | Left = OldLeft + (NewPos - OldLeft) * (CurrentTime - StartTime) / 200 = 75 + 20 * 50 / 200 = 80
|
Kannst du das bitte in Delphi- oder Pseudocode giessen?
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 29.07.16 20:43
Meine Ansätze:
- Ermittle die aktuelle Zeit (GetTickCount)
- Durchlaufe eine while-Schleife: while StartPos < EndPos do
- Stelle darin laufend die aktuelle Zeit fest
- und weiter?
oder:
- while-Schleife, solange StartTime < CurrTime
Ich habe keine konkrete Idee, wie ich das umsetzen soll.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Mathematiker
Beiträge: 2622
Erhaltene Danke: 1447
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: Fr 29.07.16 21:04
Hallo,
evtl. so, wobei ich nicht einschätzen kann, ob das bei deinem Problem hilft.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| procedure Zeitschleife(msZeit: DWord); var Dauer: double; Anfang, Ende, Frequenz : TLargeInteger; begin QueryPerformanceFrequency(Frequenz); QueryPerformanceCounter(Anfang); repeat Application.ProcessMessages; QueryPerformanceCounter(Ende); Dauer:=(Ende-Anfang)/Frequenz*1000.0; until Dauer>=msZeit; end; |
Beste Grüße
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
Für diesen Beitrag haben gedankt: galagher
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Sa 30.07.16 09:03
Mathematiker hat folgendes geschrieben : | Hallo,
evtl. so, wobei ich nicht einschätzen kann, ob das bei deinem Problem hilft. |
Nun ja, das ist tatsächlich eine funktionierende Zeitschleife, aber um das TImage zu bewegen, muss ich doch Left+1 angeben. Das läuft dann in einem Rutsch durch, während die Zeitschleife weiterläuft, bis until erfüllt ist. Selbst, wenn ich bei msZeit 1000 angebe, also 1 Sekunde: Das Image bewegt sich zügig nach rechts, die Schleife läuft 1 Sekunde.
So gesehen nützt mir das leider nichts! Ich habe keine Idee, was ich tun soll!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Sa 30.07.16 13:04
Ich schreibe heute noch etwas dazu... Bin unterwegs...
Die Formel habe ich ja aufgeschrieben.
Bei dir in etwa... am Handy geschrieben... Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| MoveWidth := iAbgelegtePosX-65 - ComputerLImage1.Left;
OriginalLeft := ComputerLImage1.Left;
ComputerLImage1.Left := OriginalLeft + VergangeneMillisekunden / DauerInMillisekunden * MoveWidth; |
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: So 31.07.16 09:05
Das macht 2 Sprünge nach rechts, eine flüssige Bewegung ist das nicht:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| var MoveWidth, OriginalLeft, VergangeneMillisekunden, DauerInMillisekunden: Integer; begin OriginalLeft := ComputerLImage1.Left; DauerInMillisekunden := 100; VergangeneMillisekunden := 0;
while Left < iAbgelegtePosX do begin Inc(VergangeneMillisekunden);
Left := OriginalLeft + VergangeneMillisekunden div DauerInMillisekunden * MoveWidth;
Form1.Refresh; end; end; |
Wenn ich VergangeneMillisekunden und DauerInMillisekunden als Double angebe, ändert das nichts am Fehler - es klappt nicht.
Ich blicke da nicht durch.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 31.07.16 14:37
Ich habe einmal meine Formel 1:1 in Quelltextform gebracht (das " * 1000 / Freq" gehört zur Ermittlung der Millisekunden)...
Das hatte ich dir eigentlich zugetraut. Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| var StartPos, EndPos: Integer; Start, Current, Freq: Int64; begin StartPos := 8; EndPos := FGui.DisplayWidth - 8 - FGui.ImageWidth; QueryPerformanceFrequency(Freq); while not Terminated do begin FGui.ImageLeft := StartPos; QueryPerformanceCounter(Start); repeat QueryPerformanceCounter(Current); FGui.ImageLeft := StartPos + Round((EndPos - StartPos) * (Current - Start) * 1000 / Freq / FAnimationDuration); until (Current - Start) * 1000 / Freq >= FAnimationDuration; FGui.ImageLeft := EndPos; Sleep(100); end; |
Im Anhang liegt ein Beispielprojekt, das dies aus einem Thread heraus macht.
Normalerweise macht man die Threadsynchronisation im Thread, nicht im Setter in der Gui. Das habe ich hier nur gemacht um den Threadquelltext für das Beispiel kurz zu halten.
Einloggen, um Attachments anzusehen!
Für diesen Beitrag haben gedankt: galagher, Mathematiker
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Di 02.08.16 18:59
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 03.08.16 02:15
(Current - Start) * 1000 / Freq ergibt die bisher abgelaufene Dauer in Millisekunden. Der Performance counter zählt in Ticks, da er sehr viel genauer als z.B. GetTickCount arbeitet, das hier aber auch gereicht hätte. Deshalb muss man diese Ticks umrechnen und da die Frequenz auf Sekunden läuft muss man das Ergebnis noch mit 1000 multiplizieren um Millisekunden zu bekommen.
Diese Formel findest du aber wie auch oben bei Mathematiker bei jedem Codeschnippsel zu genauer Zeitmessung.
Und die Formel für die aktuelle Position ist ein Dreisatz. Man setzt die in der abgelaufenen Zeit anteilig zurückgelegte Strecke proportional ins Verhältnis zu der Gesamtstrecke.
Für diesen Beitrag haben gedankt: galagher
|
|
galagher
Beiträge: 2522
Erhaltene Danke: 44
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Do 04.08.16 08:59
jaenicke hat folgendes geschrieben : | und da die Frequenz auf Sekunden läuft muss man das Ergebnis noch mit 1000 multiplizieren um Millisekunden zu bekommen. |
Soweit klar!
jaenicke hat folgendes geschrieben : | Und die Formel für die aktuelle Position ist ein Dreisatz. |
Manchmal liegt die Lösung auf der Hand, und man kommt nicht drauf!
Ich habe den Code jetzt noch für Bewegungen von rechts nach links und senkrecht angepasst und möchte ihn noch weiter verallgemeinern.
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Knulli
Beiträge: 116
Erhaltene Danke: 2
Win2k, Win7, Win10
D5, D2005, D2006, D2007, D10.4.2
|
Verfasst: Mo 05.09.16 12:15
Mach mal
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure SetSleepGranularity(); begin timeBeginPeriod(1); end;
procedure ResetSleepGranularity(); begin timeEndPeriod(1); end; |
in den Initalzie / Finalize Teil deiner Unit.
Delphi macht sowas auch. Wenn Delphi nicht läuft, dann sind Deine Sleeps alle langsamer.
Es reicht also, wenn Delphi nur im Hintergrund läuft, damit dein Programm schneller ist.
Knulli
_________________ Echte Männer schreiben Windows-Programme in Assembler unter edlin.
Für diesen Beitrag haben gedankt: galagher, jaenicke
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 05.09.16 14:31
Danke, das kannte ich auch noch nicht. Und die Doku zeigt auch warum das alle Prozesse betrifft:
Das zeigt einmal mehr weshalb der von mir gezeigte Ansatz für eine Animation sinnvoller ist.
|
|
|