Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Visible-Status von TShape in Timer-Callback Funktion ändern (https://www.delphipraxis.net/211259-visible-status-von-tshape-timer-callback-funktion-aendern.html)

palmakunkel 22. Aug 2022 17:25

Visible-Status von TShape in Timer-Callback Funktion ändern
 
Liste der Anhänge anzeigen (Anzahl: 1)
Eine von TShape abgeleitete Metronom-Komponente, deren Visible-Status sich im Rhythmus ändert. Das soll über die Timer-Callback-Funktion erfolgen (Win-API). Diese bekommt aSender übergegen. Wenn ich in der Funktion auf TShape(aSender).Visible zugreife gibt es einen Fehler. Wahrscheinlich ist das für den Profi banal, aber ich bin Autodidakt und hier an meiner Wissensgrenze. Kann mir jemand einen Tipp geben?

type
TMetronom = class(TShape)
private
{ Private-Deklarationen }
fBlinkDuration: integer;
fEnabled: boolean;
fTimerQueue: TgoTimerQueue;
...
procedure OnTimer(const ASender: TObject);
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
...
published
property BlinkDuration: integer read fBlinkDuration write fBlinkDuration;
end;

implementation

constructor TMetronom.Create(AOwner: TComponent);
begin
inherited create(AOwner);
...
FTimerQueue := TgoTimerQueue.Create;
...
end;

procedure TMetronom.OnTimer(const ASender: TObject);
begin
if fEnabled then
begin
TShape(aSender).Visible:=false;
Sleep(BlinkDuration);
TShape(aSender).Visible:=true;
end;
end;

himitsu 22. Aug 2022 18:10

AW: Visible-Status von TShape in Timer-Callback Funktion ändern
 
Zitat:

Delphi-Quellcode:
TShape(aSender).Visible

Delphi-Quellcode:
(aSender as TShape).Visible


Und dann überleg dir, warum es nun den "richtigen" Fehler gibt, bzw. warum er dort auftritt.




Warum die Variable fEnabled, anstatt direkt das Enabled des Timers durchzureichen?
Außerdem läuft der Timmer sinnlos auch dann, wenn nichts gemacht wird.

Und Sleep ... NEIN.
Da fehlt zwischendurch das Repaint und außerdem hängt dabei die Anwendung.
Lösung: Timer mit halbem Interval und dann
Delphi-Quellcode:
Visible := not Visible;




PS: [DELPHI] ... [/DELPHI]



Statt die Komponente ständig sichtbar/unsichtbar zu machen, würde ich eher empfehlen z.B. eine TPaintBox zu nehmen und nur deine Komponente im Interval neu zu zeichnen,
anstatt die halbe Form (mindestens den Parent) zu zwingen sich neu zu zeichnen, wenn deine Komponente unsichtbar wird.

palmakunkel 23. Aug 2022 11:23

AW: Visible-Status von TShape in Timer-Callback Funktion ändern
 
sehr wertvolle Hinweise, danke! Besonders den mit TPaintBox will ich einarbeiten. Aber (aSender as TShape).Visible erzeugt den gleichen Fehler, wie TShape(aSender).Visible. Ich nehme aber nicht TTimer, der ist zu ungenau, sonder die API Funktionen CreateTimerQueueTimer() nach Anlegen der Queue. Da kommt die Callback-Funktion mit dem übergebenen Zeiger nicht klar. Der zeigt offenbar nicht auf TShape, sondern ins Nirvana, oder?

TurboMagic 23. Aug 2022 11:55

AW: Visible-Status von TShape in Timer-Callback Funktion ändern
 
Vermutlich zeigt der auf fTimerQueue.
Kannst ja mal die Adressen vom Sender und dem Feld vergleichen...
Im OnTimer vom TTimer ist das Übergebene Sender Objekt ja auch das des Timers selber...

himitsu 23. Aug 2022 12:26

AW: Visible-Status von TShape in Timer-Callback Funktion ändern
 
Zitat:

Aber (aSender as TShape).Visible erzeugt den gleichen Fehler
Dürfte es eigentlich nicht.

Jetzt müsste ein Cast-Error kommen, weil ASender bestimmt der Timer ist und nicht das Shape,

aber da du eh bereits in einer Methode dieses TShape/TMetronom bist, brauchst du Sender garnicht. (Self reicht)



harter Cast
Delphi-Quellcode:
TIrgendwas(etwas)
schreibt einfach blind den Typ der Variable um (prüft nicht den Inhalt)
weicher Cast
Delphi-Quellcode:
(etwas as TIrgendwas)
prüft ob wirklich der Typ drin ist

palmakunkel 23. Aug 2022 16:47

AW: Visible-Status von TShape in Timer-Callback Funktion ändern
 
wenn in OnTimer ein Funktionsaufruf zum Umfärben der Canvas steht klappt es, wenn ich dort direkt Canvas.FillRect() aufrufe, gibt es Speicherfehler.
Die Sleep-Funktion ist sicher nicht die hohe Schule, aber da das Programm, in dem das Metronom läuft, nur Noten anzeigt, also praktisch nichts zu tun hat, stört das 50 ms-Schlafen eigentlich nicht. Wenn ich die Farbe rhythmisch wechsele mit doppelter Timer-Geschwindigkeit, sind die grau- und rot-Phasen gleich lang, so habe ich praktisch nur einen "Grau-Blitz" in einer roten Fläche.

Vielen Dank nochmal für die Tipps und die schnellen Reaktionen!

procedure TMetronom1.FillColorRed;
begin
Canvas.Brush.Color:=clRed;
Canvas.FillRect(ClientRect);
end;

procedure TMetronom1.FillColorBtnFace;
begin
Canvas.Brush.Color:=clBtnFace;
Canvas.FillRect(ClientRect);
end;

procedure TMetronom1.OnTimer(const ASender: TObject);
begin
FillColorBtnFace;
Sleep(BlinkDuration);
FillColorRed;
end;

Medium 23. Aug 2022 18:34

AW: Visible-Status von TShape in Timer-Callback Funktion ändern
 
Wenn du im Parameter "Parameter" von CreateTimerQueueTimer() dein TShape übergibst, sollte der gleichnamige Parameter der Callback-Funktion exakt denselben Wert enthalten. Ein PVOID wird vermutlich als "Pointer" übersetzt, also bloß einfach ein typfreier Wert.

Wie übergibst du denn dein Shape beim Aufruf von CreateTimerQueueTimer? Ich meine, dass es einen Unterschied macht, ob man "@MyShape" oder "Pointer(MyShape)" benutzt. Versuche mal das jeweils andere von dem was du bisher hattest.

Im Callback selbst sollte dann ein (lpParameter as TShape).Visible eigentlich gehen, es sei denn du zerstörtst das Shape zwischendurch und erstellst es neu. Dann ist der alte Pointer natürlich (höchstwahrscheinlich) ungültig.

palmakunkel 24. Aug 2022 09:07

AW: Visible-Status von TShape in Timer-Callback Funktion ändern
 
@Medium, vielen Dank! Ich benutze ein CreateTimerQueue- und Timer-Objekt von https://github.com/grijjy/DelphiTimerQueue. Das funktioniert auch gut. Dass der Callback-Funktion die Adresse des Timer-Objektes übergeben wird und nicht die vom TShape hatte ich bisher nicht kapiert.
Ich hatte eine Variante, in der ich in das Timer-Objekt fShapeAddr eingefügt habe, in der Initialisierung habe ich die TShape-Adresse da rein geladen und auf die in der Callback-Funktion zugegriffen. Das ging. Jetzt wollte ich aber ein Objekt machen, in dem die Ausgabekomponente im Zentrum steht und nicht der Timer, und da ging der Schlamassel los. Aber jetzt funktioniert es. Vielen Dank nochmal an die Mitdenker!


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:13 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz