Autor Beitrag
galagher
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 25.07.16 20:54 
Hallo!

Folgende for-Schleife:
ausblenden 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);  //Ist zB. 1
    if Odd(i) then Form1.Refresh;
  end;


Ja, ich weiss, das gehört in einen TTimer... :roll: 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?! :eyecrazy:

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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 376
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Mi 27.07.16 20:12 
Hallo,

mit folgenden Programm habe ich keinen Unterschied festgestellt:

ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 28.07.16 20:14 
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
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...

user profile iconOlafSt hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 376
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Fr 29.07.16 00:08 
Setze doch mal die Priorität Deines Programms von "normal" auf "high". Ändert sich was?

Gruß GuaAck
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Fr 29.07.16 07:57 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Left = OldLeft + (NewPos - OldLeft) * (CurrentTime - StartTime) / 200 = 75 + 20 * 50 / 200 = 80
Kannst du das bitte in Delphi- oder Pseudocode giessen? :mrgreen:

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 2622
Erhaltene Danke: 1447

Win 7, 8.1, 10
Delphi 5, 7, 10.1
BeitragVerfasst: Fr 29.07.16 21:04 
Hallo,
evtl. so, wobei ich nicht einschätzen kann, ob das bei deinem Problem hilft.
ausblenden 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;  ///je nachdem, ob es gebraucht wird
    QueryPerformanceCounter(Ende);
    Dauer:=(Ende-Anfang)/Frequenz*1000.0;
    ///hier irgendetwas machen, zeichnen ....
  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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Sa 30.07.16 09:03 
user profile iconMathematiker hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
MoveWidth := iAbgelegtePosX-65 - ComputerLImage1.Left; 
// Bewegungsweite

OriginalLeft := ComputerLImage1.Left;

// Und in der Schleife
ComputerLImage1.Left := OriginalLeft + VergangeneMillisekunden / DauerInMillisekunden * MoveWidth;
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: So 31.07.16 09:05 
Das macht 2 Sprünge nach rechts, eine flüssige Bewegung ist das nicht:
ausblenden 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  //Left bezieht sich auf das TImage!
  begin
    Inc(VergangeneMillisekunden);  //Wie zähle ich VergangeneMillisekunden?

    //Hier kommt: "[DCC Fehler] CardsHandling.pas(884): E2010 Inkompatible Typen: 'Integer' und 'Extended'"
    {Left := OriginalLeft + VergangeneMillisekunden / DauerInMillisekunden * MoveWidth;}

    //Also mache ich es so:
    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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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. ;-)
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Di 02.08.16 18:59 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das hatte ich dir eigentlich zugetraut. ;-)

Ich habe die Stellen kommentiert, mit denen ich nichts anfangen konnte (und kann, solange ich keinen Quellcode dazu sehe!):
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
var
  StartPos, EndPos: Integer;
  Start, Current, Freq: Int64;
begin
  StartPos := 8;
  EndPos := FGui.DisplayWidth - 8 - FGui.ImageWidth;

  //Der Name erklärt zwar, was das macht, aber zunächst dachte ich,
  //an Freq wird ja gar nichts zugewiesen. Das macht aber wohl QueryPerformanceFrequency!
  QueryPerformanceFrequency(Freq);
  while not Terminated do
  begin
    FGui.ImageLeft := StartPos;
 
   QueryPerformanceCounter(Start);  //Siehe obigen Kommentar!

    repeat
      QueryPerformanceCounter(Current);  //Auch das war/ist mir nicht so ganz klar, wie das arbeitet!

      //Auf diese Formel (auch auf die Anweisung im until) wäre ich von selbst nie gekommen!
      FGui.ImageLeft := StartPos + Round((EndPos - StartPos) * (Current - Start) * 1000 / Freq / FAnimationDuration);
    until (Current - Start) * 1000 / Freq >= FAnimationDuration;
    FGui.ImageLeft := EndPos;
    Sleep(100);
  end;


Ich werde nach den entsprechenden Windows-API-Prozeduren googlen, um das besser zu verstehen!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 04.08.16 08:59 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
und da die Frequenz auf Sekunden läuft muss man das Ergebnis noch mit 1000 multiplizieren um Millisekunden zu bekommen.
Soweit klar!

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 116
Erhaltene Danke: 2

Win2k, Win7, Win10
D5, D2005, D2006, D2007, D10.4.2
BeitragVerfasst: Mo 05.09.16 12:15 
Mach mal
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 05.09.16 14:31 
Danke, das kannte ich auch noch nicht. Und die Doku zeigt auch warum das alle Prozesse betrifft:
msdn.microsoft.com/d...757624(v=vs.85).aspx hat folgendes geschrieben:
This function affects a global Windows setting. Windows uses the lowest value (that is, highest resolution) requested by any process.


Das zeigt einmal mehr weshalb der von mir gezeigte Ansatz für eine Animation sinnvoller ist.