Label in onclick anzeigen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
schröttel
Beiträge: 5
Registriert: Do 2. Mai 2024, 14:08

Label in onclick anzeigen

Beitrag von schröttel »

Hallo,
ich hätte gerne da mal ein Sandkastenproblem. :D

In einem onclick eines Button möchte ich die Caption eines Labels ändern und sofort anzeigen. Anscheinend wird aber erst nach Beendigung der onlick Prozedur das Label angezeigt, weil nur die 2. Änderung der Caption sichtbar wird.
Da gibt es doch sicher eine Methode die das sofortige Anzeigen auslöst.

Code: Alles auswählen

procedure TCtrlpanel.Home(Sender: TObject);
begin
  Meldung.Caption := '1. Anzeige aus Home';
  delay(3000);
  Meldung.Caption := '2. Anzeige aus Home';
  delay(3000);
end;

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Label in onclick anzeigen

Beitrag von m.fuchs »

Ja, gibt es:

Code: Alles auswählen

procedure TCtrlpanel.Home(Sender: TObject);
begin
  Meldung.Caption := '1. Anzeige aus Home';
  Application.ProcessMessages;
  delay(3000);
  Meldung.Caption := '2. Anzeige aus Home';
  Application.ProcessMessages;
  delay(3000);
end;
Durch den Aufruf von Application.ProcessMessages arbeitet dein Programm erst einmal alle anstehenden Nachrichten ab (dazu gehört auch der Zeichenbefehl für dein Label) und macht erst dann mit dem Delay weiter. Dieses Abarbeiten wird normalerweise immer erledigt, wenn das Programm gerade nichts zu tun hat - bei einem Delay hat es das aber.

Und damit kommen wir auch schon zum tieferen Problem: das ist eigentlich keine saubere Lösung. In diesem Fall würde ich das eher mit einem Timer machen. Je nachdem was der eigentliche Zweck ist auch anders.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 1206
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Manjaro Linux, Mint und Windows 10 ,Lazarus 3.99, FPC-Version: 3.3.1
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

Re: Label in onclick anzeigen

Beitrag von kralle »

Moin,

Wäre der Speedbutton dafür nicht geeignet?

Gruß Heiko
OS: MX Linux, Linux Mint und Windows 10
FPC-Version: 3.3.1 , Lazarus 3.99
+ Delphi XE7SP1

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Label in onclick anzeigen

Beitrag von m.fuchs »

kralle hat geschrieben: Do 2. Mai 2024, 14:44 Wäre der Speedbutton dafür nicht geeignet?
Da verhält sich die MessageQueue aber nicht anders. Oder was meintest du genau?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 1206
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Manjaro Linux, Mint und Windows 10 ,Lazarus 3.99, FPC-Version: 3.3.1
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

Re: Label in onclick anzeigen

Beitrag von kralle »

Ich dachte das er sich anders verhält, weil er ja beim Klick ja auch eine andere Grafik anzeigen kann.

Habe Ihn selber noch nicht eingesetzt, sondern nur von gelesen.

Gruß Heiko
OS: MX Linux, Linux Mint und Windows 10
FPC-Version: 3.3.1 , Lazarus 3.99
+ Delphi XE7SP1

schröttel
Beiträge: 5
Registriert: Do 2. Mai 2024, 14:08

Re: Label in onclick anzeigen

Beitrag von schröttel »

Danke, mit Application.ProcessMessages; funktioniert es. Mir war nicht klar wie die Abarbeitung der Prozessmeldungen passiert. Die delays sind nur zum Test dort, damit man was sieht. Die eigentliche Prozedur zeigt eine Meldung an, arbeitet dann ein Unterprogramm ab und gibt dann eine Fertigmeldung aus.
Mit einem Speedbutton funktioniert es übrigens auch nur mit Application.ProcessMessages;.

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

Re: Label in onclick anzeigen

Beitrag von Mathias »

schröttel hat geschrieben: Do 2. Mai 2024, 14:25 Hallo,
ich hätte gerne da mal ein Sandkastenproblem. :D

In einem onclick eines Button möchte ich die Caption eines Labels ändern und sofort anzeigen. Anscheinend wird aber erst nach Beendigung der onlick Prozedur das Label angezeigt, weil nur die 2. Änderung der Caption sichtbar wird.
Da gibt es doch sicher eine Methode die das sofortige Anzeigen auslöst.

Code: Alles auswählen

procedure TCtrlpanel.Home(Sender: TObject);
begin
  Meldung.Caption := '1. Anzeige aus Home';
  delay(3000);
  Meldung.Caption := '2. Anzeige aus Home';
  delay(3000);
end;
Wies machst du dies nicht mit einem Timer ?
Dann wird dir schön brav alles ausgegeben.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Label in onclick anzeigen

Beitrag von m.fuchs »

schröttel hat geschrieben: Do 2. Mai 2024, 16:22 Die eigentliche Prozedur zeigt eine Meldung an, arbeitet dann ein Unterprogramm ab und gibt dann eine Fertigmeldung aus.
Jo, dachte ich mir schon - je nachdem wie dein Programm funktioniert, solltest du noch folgendes Bedenken:
  • Wenn dein Programm während der Abarbeitung keinerlei Benutzereingaben erhalten muss, solltest du alle Eingabekomponenten disablen, damit da nicht ein User beispielsweise dreißig mal klickt und sich wundert dass nix passiert. Ist dann dein Unterprogramm durch, werden diese Klicks verarbeitet.
  • Soll hingegen eine Benutzerinteraktion notwendig sein, dann müsstest du dein Unterprogramm in einen Thread auslagern.
Mehr zu diesen Themen findest du hier: https://wiki.freepascal.org/Multithread ... n_Tutorial
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

schröttel
Beiträge: 5
Registriert: Do 2. Mai 2024, 14:08

Re: Label in onclick anzeigen

Beitrag von schröttel »

Wie schon gesagt wird ein Unterprogramm aufgerufen und gewartet bis das fertig ist.
Das Unterprogramm läuft allerdings auf einem Arduino ab und steuert einen Portalroboter.
Vom FPC Programm erhält der Arduino verschiedene Steuerbefehle und arbeitet diese selbstständig ab und meldet die Ausführung zurück.
Die serielle Kommunikation zwischen FPC und Arduino erfolgt über die UNIT Synaser.
Allerdings funktioniert die Übertragung von Strings noch nicht stabil, da bin ich noch in der Testphase.

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: Label in onclick anzeigen

Beitrag von MmVisual »

Ein Delay ist quasi verboten. Auch wenn es funktioniert macht es nur Probleme.

Bei allen Dingen wo man im Code warten muss, sollte man unbedingt einen Timer einsetzen.

Wenn etwas Asynchron, also direkt nach einer Taste ausgeführt werden soll, so kann man sich selbst eine Botschaft die die Message Queue schreiben, Beispiel:

Code: Alles auswählen

Application.QueueAsyncCall(@<Funktion die aufgeruden werdne soll>,<Pointer auf eine Datenstruktur>);
Somit kann man verschachtelte komplexe Aufrufe mit QueueAsyncCall voneinander korrekt trennen, die dann mit der Botschaftenschleife nacheinander aufgerufen werden.

Wenn man ein neues Windows hat, wie z.B. Win11 und man packt zu viele Delay's da rein, das mag Windows überhaupt nicht mehr dass so eine Funktion quasi aufgerufen wird und die sich nicht beendet. Neuerdings überwacht Windows die Dauer einer Funktion.
Daher >>> programmier es gleich "richtig".

Beispiel einer konkreten Anwenung von "QueueAsyncCall". Log Meldungen in das Log schreiben benötigen immer ziemlich Zeit, damit wird der aktuelle Prozess verlangsamt. Damit das ganze dennoch in der korrekten Reihenfolge im Log erscheint und nichts verloren geht kann man das über diese QueueAsyncCall lösen.

Code: Alles auswählen

type  TLogMsgData = record // Record für Log in das Protokoll mit DoLog()
    strLogTxt: string;
    dtLog: TDateTime;
  end;
  PLogMsgData = ^TLogMsgData;  

procedure TfrmMain.DoLog(strLogTxt: string);
var LogMsgToSend: PLogMsgData;
Begin
  New(LogMsgToSend); // Speicher reservieren
  LogMsgToSend^.strLogTxt:= strLogTxt;
  LogMsgToSend^.dtLog := Now;
  Application.QueueAsyncCall(@DoLogAsyncQueue, PtrInt(LogMsgToSend));
End;
procedure TfrmMain.DoLogAsyncQueue(Data: PtrInt);
var
  ReceivedLogMsg: TLogMsgData;
begin
  ReceivedLogMsg := PLogMsgData(Data)^; 
  try // Fehler im Log ignorieren
    : : :
  finally
    Dispose(PLogMsgData(Data)); // Speicher wieder frei geben
  end;   
end;

EleLa - Elektronik Lagerverwaltung - www.elela.de

schröttel
Beiträge: 5
Registriert: Do 2. Mai 2024, 14:08

Re: Label in onclick anzeigen

Beitrag von schröttel »

Puh, da muss ich noch einiges verinnerlichen. Ich komme noch aus der sequentiellen Welt. Multithreads und Messagequeues sind schon unheimlich, aber das ein Betriebssystem die Ausführungsdauer meiner Prozeduren überwacht gehört sich einfach nicht. :shock:
Danke für die Mühe und ich werde mich da schon noch durchbeißen.

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: Label in onclick anzeigen

Beitrag von MmVisual »

Ich habe mal ein kleines Projekt angehängt wie so etwas richtig geht.
Das wichtigste: Niemals warten im Code, bzw. das Warten über einen Bearbeitungsschritt abarbeiten.

Mit "Start" kann man den Timer aktivieren, mit "Stop" wieder deaktivieren.

Nach "Start" ist der Schritt 0 aktiv.
Dann drückt man die Taste "Setze Schritt auf 1" und der Schritt 1 wartet 3 Sekunden und setzt dann den Schritt auf 2.
Schritt 2 wartet auf ein Ereignis (die andere Taste) und schaltet dann den Schritt auf 3 weiter.
Schritt 3 wartet 5 Sekunden und schaltet danach auf Schritt 4 Weiter
Schritt 4 macht nichts und springt nur zurück zu Schritt 2

Der Timer wird alle 100ms aufgerufen, springt mit Case an die Schritt-Nummer iStep und wenn das IF nicht erfüllt ist wird der Timer beendet und kommt erneut nach 100ms und schaut wieder nach ob es nun weiter geht - somit kein Warten im Code.

Zudem kann man hier sehr gute den Schrittwechsel überwachen und in einer Liste aufzeichnen.
Damit lassen sich sehr komplexe Konstrukte abbilden und man kann die Schritt-Nummern schön "Sortieren" indem man z.B. ab 1 ist Initialisierung, ab 10 Funktion A, ab 50 Funktion B, ab 1000 wieder was usw...
Aus diesen Schritt-Nummern kann man sich Konstante Bezeichner machen, z.B. "Const S0InitStart = 0;", damit sieht man anhand dem Bezeicher schon was es für ein Schritt sein soll.
Schritte, die immer den nächsten aufrufen, sollte man immer mit "iStep += 1;" oder "iStep -= 1;" rechen, denn sollte man mal Schritte verschieben, dann ist diese Abfolge in sich immer noch konsistent.

Anhand der Schritt Nummer kann man jederzeit sehen in welchem Code das Programm nun genau steckt. Da ist der dann einfach im Schritt XXX und genau dieser kleine Codeschnipsel (von dieser sehr langen Schrittabfolge) ist dann der Übeltäter wenn etwas nicht geht. Somit die Diagnose wird viel einfacher. GoTo Befehle werden unnötig, da man nur zu anderen Schrittnummern wechselt. Durch die Schrittaufzeichnung weiß man dann jederzeit welche Schritte zuvor ausgeführt wurden.
Selbst wenn du ein Code analysieren musst, den andere geschrieben haben, braucht du nur die Schritt-Nummern nach gehen und findest dich sehr schnell in dem fremden Code zurecht, ohne dass du den kompletten Ablauf (der durchaus 1000 und mehr Zeilen haben könnte) verstehen musst.

Und exakt genau die gleiche Technik kann man in einem µC oder anderen Steuerung verwenden. Der Main-Loop ruft zyklisch immer ein anders Modul auf, dieses hat die Schrittkette und wenn das Signal nicht erreicht ist springt dieses Modul einfach wieder raus zum Main-Loop. Somit kann der Main-Loop problemlos unterschiedliche Module aufrufen, die quasi alle parallel abgearbeitet werden. Damit erstpart man sich das Betriebssystem (FreeOS oder andere) auf so einem Mikrocontroller und die Bearbeitung geht meist schneller. Also auch im Mikrocontroller NIEMALS warten im Code.
Als Seiteneffekt kann man im Main-Loop einen Zähler implementieren, den man jede Sekunde ausgibt und nullt. Damit sieht man sofort, wenn der Zähler z.B. immer bei 100000 ist und dann plötzlich runter geht auf 100, dass man da wohl etwas rein gebaut hat was zu viel Rechenleistung benötigt (z.B. ein Interrupt der nun zu oft kommt). Bei einer Sequenziellen Programmierung wäre so etwas nicht machbar.

Wenn du einmal diese Technik verinnerlichst hast, und alles nach diesem einen Schema implementierst, also egal wo (PC Programm, Mikrocontroller oder SPS Steuerung), dann wirst du auch in 30 Jahren keine Probleme bekommen (eigene Erfahrung) und Projekte selbst nach vielen Jahren problemlos warten können, auch wenn du schon wieder die hälfte vergessen hast (das ist dann so wenn man älter wird).
Dateianhänge
Bearbeitungsschrittkette.zip
(139.43 KiB) 23-mal heruntergeladen
EleLa - Elektronik Lagerverwaltung - www.elela.de

schröttel
Beiträge: 5
Registriert: Do 2. Mai 2024, 14:08

Re: Label in onclick anzeigen

Beitrag von schröttel »

Danke für die sehr ausführliche Beschreibung. Das hört sich eigentlich nicht so kompliziert an. Mal sehen ob ich dein Beispiel nachvollziehen kann. Zum Glück muss ich damit kein Geld verdienen und kann mir Zeit lassen.

Antworten