For-Schleife mit Ausgabe wie Diashow

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
InfoSchülerktog
Beiträge: 9
Registriert: Fr 6. Mär 2015, 09:07

For-Schleife mit Ausgabe wie Diashow

Beitrag von InfoSchülerktog »

Hallo, ich habe folgendes Problem:
Für eine Anwendung möchte mir durch einem einfach ButtonClick 20 Würfelbilder NACHEINANDER anzeigen lassen (stark vereinfachtes Beispiel).
Das heißt, ich möchte einmal klicken und die Bilder sollen wie von Geisterhand nacheinander angezeigt werden (wie eine Diashow).
Ich würde nun gern wissen, wie ich das hinkriege.
Den Quellcode habe ich euch reingestellt (derzeit zeigt er einfach nur das letzte Bild; das kontrolliere ich nebenbei noch mit einer Variablenausgabe der Würfelaugenzahl, die ich hier nicht mit aufgeführt habe, da sie es nur unnötig komplizierter macht).

prcoedure TForm1.Button1Click(Sender: TObject);
begin
For Zaehler := 1 To 20 Do
begin
randomize;
sleep(150); [liefert andere Zufallszahlen]
wuerfel:=Random(6)+1;

case wuerfel of

1: Wuerfel1Image.Picture.LoadFromFile('\würfel1.png'); [Die Bilder sind jeweils Würfel mit der entsprechenden Augenzahl]
2: Wuerfel1Image.Picture.LoadFromFile('\würfel2.png');
3: Wuerfel1Image.Picture.LoadFromFile('\würfel3.png');
4: Wuerfel1Image.Picture.LoadFromFile('\würfel4.png');
5: Wuerfel1Image.Picture.LoadFromFile('\würfel5.png');
6: Wuerfel1Image.Picture.LoadFromFile('\würfel6.png');

end; end; end;

Vielen Dank im Voraus für eure Hilfe :)

Warf
Beiträge: 1910
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von Warf »

Ich würde dir an dieser Stelle empfehlen einen Timer zu machen.

Den Timer stellst du dann auf Enabled = False, und den Intervall auf die Länge, wie lang ein Bild angezeigt werden soll.

Code: Alles auswählen

TForm1 = class(TForm)
...
private
FImageIndex: Integer;
...
end;
...
 
prcoedure TForm1.Button1Click(Sender: TObject);
begin
  FImageIndex:=1;
  ImageTimer.Enabled:=True;
end;
 
procedure TForm1.ImageTimerTimer(Sender: TObject);
  ImageTimer.Enabled:=False;
  Wuerfel1Image.Picture.LoadFromFile('\würfel'+IntToStr(Random(6)+1)+'.png');
  inc(FImageIndex);
  if FImageIndex = 20 then
  begin
    //Hier was Passieren soll nachdem alle Würfe durch sind
  end
  else
    ImageTimer.Enabled:=True;
begin
 
end;

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von mschnell »

InfoSchülerktog hat geschrieben:prcoedure TForm1.Button1Click(Sender: TObject);
begin
For Zaehler := 1 To 20 Do
begin
randomize;
sleep(150); [liefert andere Zufallszahlen]
....


Sorry. Aber darf man in Lazarus und ähnlichen Systemen nicht programnmieren ! :(

"sleep" ist im Main-Thread nicht erlaubt, sondern nur in "Worker-Threads". (Thread-Programmieru8ng bekommen wir aber erst später...)

Der Main-Thread darf niemals auf irgendetwas warten.

Solche Systeme heißen "Event-orientiert". Da muss man jede Aktion als "Event" programmieren. Ein "Event" (in diesem Sinne) ist ein Unterprogramm, das vom System aufgerufen wird, irgendetwas macht, und dann wieder verlassen wird ("Run-To-Completion-Event").

Um Zeitgesteuerte Aktionen zu machen gibt es TTimer, der regelmäßig ein Event aufruft.

-Michael

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von theo »

mschnell hat geschrieben:Der Main-Thread darf niemals auf irgendetwas warten.

Seit wann? Wo steht das?

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von Mathias »

Ich würde zumindest ein Application.ProcessMessages; einbauen, ansonsten kann das Programm nicht unterbrochen werden, bis die Schleife durch ist.

Beispiel:

Code: Alles auswählen

var
  Abbruch: boolean;
 
procedure TForm1.StopClick(Sender: TObject);
begin
  Abbruch := True;
end;
 
procedure TForm1.StartClick(Sender: TObject);
begin
  Abbruch := False;
  repeat
    Canvas.Pen.Color := Random($FFFFFF);
    Canvas.LineTo(Random(ClientWidth), Random(ClientHeight));
    sleep(100);
    Application.ProcessMessages;
    if Abbruch then Exit;
  until 1 = 2;
end;


Wie Warf schon schreibt, ein Timer ist eleganter.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

InfoSchülerktog
Beiträge: 9
Registriert: Fr 6. Mär 2015, 09:07

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von InfoSchülerktog »

Also erstmal danke für die vielen Antworten.

@ warf, ich bekomme da ständig einen Compilerfehler in der "ImageTimer.Enabled:=True;"-Zeile, das scheint so nicht zu funktionieren.
External SIGSEGV - den Fehler hatte ich schon oftmals, lösen konnte ich ihn nur indem ich die Routinen umgehe (wobei ich hier leider nicht weiß wie).
Das liegt dann meist nicht am Programm an sich, sondern eben am LazarusCompiler der (Lazarus ist ja free) eben nicht so perfekt ist wie ein DelphiCompiler.

@ mschnell ich habe das Beispiel stark vereinfacht. diese procedure soll in Form9 ablaufen, ist also nicht in der MainForm. Das mit dem sleep funktioniert soweit ja auch super, nur klappt das mit der zeitversetzten Anzeige eben nicht.

Deshalb frage ich euch, ob ihr außer der Timer Variante die bei Lazarus offenbar nicht funktioniert noch eine andere Möglichkeit kennt? Danke :)

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von theo »

InfoSchülerktog hat geschrieben: Das liegt dann meist nicht am Programm an sich, sondern eben am LazarusCompiler der (Lazarus ist ja free) eben nicht so perfekt ist wie ein DelphiCompiler.


Interessante These. :lol:

Also wenn ich gegen einen Baum fahre, ist das halt weil ich nur einen VW habe und keinen Audi?

Warf
Beiträge: 1910
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von Warf »

InfoSchülerktog hat geschrieben:ich bekomme da ständig einen Compilerfehler in der "ImageTimer.Enabled:=True;"-Zeile, das scheint so nicht zu funktionieren.
External SIGSEGV - den Fehler hatte ich schon oftmals, lösen konnte ich ihn nur indem ich die Routinen umgehe (wobei ich hier leider nicht weiß wie).
Das liegt dann meist nicht am Programm an sich, sondern eben am LazarusCompiler der (Lazarus ist ja free) eben nicht so perfekt ist wie ein DelphiCompiler.


Grundsätzlich sind Delphi und FreePascal 2 unterschiedliche Sprachen, und ich muss sagen, ich finde den FPC weitaus besser als Delphi, die Probleme die du hast könnten aufgrund falsche Projekt Einstellungen zustande kommen.

InfoSchülerktog
Beiträge: 9
Registriert: Fr 6. Mär 2015, 09:07

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von InfoSchülerktog »

Also das Problem ist, dass es auch nicht funktioniert, wenn ich den Debugger komplett ausschalte. Es muss also ein anderes Problem sein.
Der External: SIGSEGV kann ja vieles bedeuten, er zeigt mir halt direkt diese eine Zeile an, wo ich den Timer an bzw. ausschalte (das Programm läuft mit dem Timer schon super, nur kann ich ihn halt nicht stoppen, weshalb es sich logischer weise immer aufhängt^^).

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von theo »

InfoSchülerktog hat geschrieben:Also das Problem ist, dass es auch nicht funktioniert, wenn ich den Debugger komplett ausschalte. Es muss also ein anderes Problem sein.
Der External: SIGSEGV kann ja vieles bedeuten, er zeigt mir halt direkt diese eine Zeile an, wo ich den Timer an bzw. ausschalte (das Programm läuft mit dem Timer schon super, nur kann ich ihn halt nicht stoppen, weshalb es sich logischer weise immer aufhängt^^).


Jetzt könnte ich die Glaskugel holen, oder du könntest deinen Code zeigen.
Was ist dir lieber?

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von Mathias »

So sollte es klappen. :wink:

Code: Alles auswählen

var
  Zaehler: integer;
  FileList: TStringList;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Inc(Zaehler);
  if Zaehler = 20 then begin
    Timer1.Enabled := False;
  end;
  Image1.Picture.LoadFromFile(FileList[Random(FileList.Count)]);
end;
 
procedure TForm1.StartClick(Sender: TObject);
begin
  Timer1.Enabled := True;
  Zaehler := 0;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  FileList := FindAllFiles('.', '*.png;*.bmp', False);
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FileList.Free;
end;
 
procedure TForm1.StopClick(Sender: TObject);
begin
  Timer1.Enabled := False;
  Image1.Picture.Clear;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von mschnell »

InfoSchülerktog hat geschrieben:@ mschnell ich habe das Beispiel stark vereinfacht. diese procedure soll in Form9 ablaufen, ist also nicht in der MainForm.


Es geht nicht um "MainForm" sondern um "MainThread" (auch GUI-Thread genannt). Alle Forms werden vom Main (GUI)-Thread gemanaged. Und (nur) dieser Thread ist in Lazarus (wenn eine "Application" programmiert wird) dem "Event-Orientierten Programmieren" http://de.wikipedia.org/wiki/Ereignis_% ... mierung%29 und damit dem "Run-To-Completion" Paradigma unterworfen und darf deshalb nicht warten (potentiell lang-dauenrnde Schleife oder sleep).

InfoSchülerktog hat geschrieben:Das mit dem sleep funktioniert soweit ja auch super, nur klappt das mit der zeitversetzten Anzeige eben nicht.
Wenn man um die Grundlagen des verwendeten infrastruktur-Systems herumprogrammiert muss man mit unerwarteten Effekten rechen.

InfoSchülerktog hat geschrieben:Deshalb frage ich euch, ob ihr außer der Timer Variante die bei Lazarus offenbar nicht funktioniert noch eine andere Möglichkeit kennt? Danke :)
Natürlich muss man nicht unbedingt eine Lararus Applikation machen. Z.B. ein "Kommandozeilen-Programm" wird von Lazarus nicht Ereignis-Orientiert angelegt.

-Michael

mschnell
Beiträge: 3444
Registriert: Mo 11. Sep 2006, 10:24
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ)
CPU-Target: X32 / X64 / ARMv5
Wohnort: Krefeld

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von mschnell »

InfoSchülerktog hat geschrieben: Das liegt dann meist nicht am Programm an sich, sondern eben am LazarusCompiler der (Lazarus ist ja free) eben nicht so perfekt ist wie ein DelphiCompiler.


Völliger Unsinn !

Linux ist auch "Free" und eines der (unter Berücksichtihgung der Komplexität) zuverlässigsten, schnellsten und (als Basis von Android) weit verbreitetsten Betriebssysteme (also Programme) überhaupt.

-Michael

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von theo »

@mschnell: Könntest du mir die obige Frage bitte noch beantworten? Das ist neu für mich.

viewtopic.php?p=76026#p76026

Warum darf ein Main-Thread nicht 150 ms sleepen? Wo steht das? Was passiert dann?

Patito
Beiträge: 203
Registriert: Di 22. Sep 2009, 13:08
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: For-Schleife mit Ausgabe wie Diashow

Beitrag von Patito »

theo hat geschrieben:
Warum darf ein Main-Thread nicht 150 ms sleepen? Wo steht das? Was passiert dann?


Passieren sollte nicht viel. Aber falls eine Anwendung im Hauptthread zu lange nicht reagiert bringt
Windows ein Popup und fragt den User, ob es die Anwendung killen soll. Sehr unschön sowas...

Unter Windows muss man praktisch in alles was im Main-Thread länger als eine Sekunde braucht
idiotischen "bitte bitte nicht killen"-Code für Windows einbauen.

Daher finde ich es schon verständlich wenn jemand so ein Sleep prinzipiell ablehnt.

Antworten