![]() |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Mal ganz egal woran es liegt oder auch nicht.
Ich fasse zusammen: Greif in einem Thread NICHT auf die VCL zu :!: Und generell auch nicht ohne weiteres auf Objekte die außerhalb des Threads benutzt werden :!: Die Sache ist die: Je nachdem KANN es gut gehen. Vielleicht geht es dann 99 von 100 mal gut. Und das 100. Mal bricht alles zusammen und du weißt nicht woher das auf einmal kam. Wollte das nur noch mal klar machen weil ich das Gefühl habe dass du glaubst dass wir dich nur aus Spaß oder Prinzip warnen "weil man das nicht" macht. Es ist aber tatsächlich ein richtiger Fehler mit dem du dir früher oder später ins Knie schießen wirst. |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Dazu gibt es auch gerade einen aktuellen Blogeintrag.
![]() Dort wird auch ein Beispiel gezeigt, das dem Thema hier sehr ähnlich ist: Zitat:
|
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Nach vielem & langen suchen & lesen bin ich ein klein wenig schlauer geworden - so wirklich verstanden hab ich das allerdings immer noch nicht, wieso genau das nicht funktioniert...
Nach dem Beispiel von Sir Rufo u. a. ![]() Mein Versuch nun, die Bitmap mittels IVMRMixerBitmap9 in den VMR9-Renderer zu schieben, ging wie erwartet in die Hose. Wie beim normalen Canvas: Man sieht kurz was, danach nicht mehr. Mittlerweile qualmt die Birne und ich sehe die Bits vor lauter Maps nicht mehr. Ich bin doch sicher nicht der erste auf diesem Planeten, der so etwas versucht. Gibt's da nicht irgendeine andere Möglichkeit/Krücke, das zu lösen ? Mittels DIB o. ä. ? |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Delphi-Quellcode:
Das komplette Projekt liegt auch im Anhang.
type
TTestThread = class(TThread) protected procedure Execute; override; end; TfrmThreadDemo = class(TForm) procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormPaint(Sender: TObject); private FTestThread: TTestThread; FExampleBitmap: TBitmap; end; var frmThreadDemo: TfrmThreadDemo; implementation {$R *.dfm} { TTestThread } procedure TTestThread.Execute; var NewBitmap: TBitmap; begin while not Terminated do begin NewBitmap := TBitmap.Create; try NewBitmap.SetSize(200, 200); NewBitmap.Canvas.MoveTo(Random(200), Random(200)); NewBitmap.Canvas.LineTo(Random(200), Random(200)); System.TMonitor.Enter(frmThreadDemo.FExampleBitmap); try frmThreadDemo.FExampleBitmap.ReleaseHandle; frmThreadDemo.FExampleBitmap.Handle := NewBitmap.ReleaseHandle; finally System.TMonitor.Exit(frmThreadDemo.FExampleBitmap); end; TThread.Synchronize(nil, procedure begin frmThreadDemo.Invalidate; end); finally NewBitmap.Free; end; Sleep(10); end; end; procedure TfrmThreadDemo.FormDestroy(Sender: TObject); begin FTestThread.Free; FExampleBitmap.Free; end; procedure TfrmThreadDemo.FormCreate(Sender: TObject); begin FExampleBitmap := TBitmap.Create; FTestThread := TTestThread.Create; end; procedure TfrmThreadDemo.FormPaint(Sender: TObject); begin System.TMonitor.Enter(frmThreadDemo.FExampleBitmap); try Canvas.Draw(0, 0, FExampleBitmap); finally System.TMonitor.Exit(frmThreadDemo.FExampleBitmap); end; end; |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Liste der Anhänge anzeigen (Anzahl: 1)
Das mit den Handles zuweisen hat hier auch nur bedingt geklappt. Der Effekt wie bei meinen weiteren Versuchen:
Die Anzeige kommt, keine Fehler - aber irgendwann friert das OSD ein, obwohl der Datenstrom / Generierung der Quell-BitMap weiter läuft. Synchronize kann ich hier nicht nutzen, weil ich (im eigentlichen Programm) nicht explizit einen Thread selbst mache, sondern der Thread-Kontext offensichtlich durch den Direct-Show-Filter (Data-Sink Transport-Stream) ensteht - ich habe jedenfalls verschiedene Thread-IDs. Mittlerweile scheint es dauerhaft (!?) zu funzen. Was hab ich für "Safe" geändert ? Aufruf des OSD aus dem Parser:
Delphi-Quellcode:
Zuweisung des Image im OSD:
procedure TOSD_data.OnReceiveData(Counter : DWORD);
begin if NOT FEnable then exit; FormMain.lbl_CountData.Caption := inttostr(FCount); // Visualisierungs-Krücke _TextOut(0, 0, inttostr(Counter)); FOutputCS.Enter; try FormOSD.OSDUpdate(FBMOSD); finally FOutputCS.Leave; end; inc(FCount); end;
Delphi-Quellcode:
Das läuft nun tadellos ohne Exception (auch vorher noch nie) oder Hänger auch über Nacht. Ob ich den Rechner anderweitig stresse, scheint keine Rolle zu spielen.
procedure TFormOSD.OSDupdate(BM : TBitMap);
begin if NOT Visible then exit; FormMain.lbl_CountOSD.Caption := inttostr(FCount); // Visualisierungs-Krücke inc(FCount); FInputCS.Enter; try if Assigned(BM) then Image.Picture.Bitmap.Assign(BM); finally FInputCS.Leave; end; end; Ich hab mein komplexes Projekt mal stark vereinfacht und als Anhang mit EXE beigefügt. Das ganze funktioniert wie folgt, besteht aus - Form Main: mit 3 Buttons (als Toggle) und 3 Labels zur "Visualisierung". Dazu hilfsweise ein Thread, der den Datenstrom simuliert. Hier wird einfach nur ein Counter hochgezählt. Die Wiederholrate ist hier mit Sleep(Randomzahl) zwischen 50 und 250 ms angelegt, damit das "wie in echt" zufällig ist. - Unit OSD_Data: Entspricht meinem Daten-Parser. Wird getriggert durch den Thread und bekommt die forlaufende Zahl, welche einfach nur ein eine (formatierte) BitMap geschrieben wird. Ein weiterer interner Zähler (<= Thread-Counter) zählt die Aufrufe mit, wenn solange der Parser aktiv (mitlesen) ist. "Enable" und "ShowData" wird von der Main-Form gesteuert. - Form OSD: Ist einfach nur eine Anzeige der fortlaufend generierten Parser-Bitmap und wird indirekt von der Main-Form über den Parser/OSD-Data gesteuert. D. h., ausschliesslich der Parser greift (direkt) auf diese Form zu. Aufruf von OSD_Show zeigt die Form an oder schliesst diese, OSD_Update "assigned" die Parser-Bitmap auf das interne Image. Funktion der Buttons: Sind als Toggle ausgelegt, d.h. Klick -> aus, Klick -> an usw. - Start/Stop Source Startet/pausiert den Thread. Das Label neben dem Button zeigt die generierte, fortlaufende Zahl an. Hat der Thread (Daten-Strom) Pause, passiert logo nix im Parser und OSD. - Start/Stop Parser: Wie Button "Start/Stop Source". Im eigentlichen Programm dient das zum Ein-/Ausschalten des Hintergrund-Monitoring/Datemsammeln (auch ohne OSD). Das Label zum Button zeigt die tatsächlich gelesenen "Datenpakete" an. - Start/Stop OSD: Wie Button "Start/Stop Source". OSD_Show intialisiert jedes mal das Image in grün mit "Hello World !". Solange Source und Parser auf STOP sind, passiert nix. Bei OSD_update wird das Image rot mit der aktuellen Zahl der Source-Threads. Erstellt mit Delphi 2009 auf Win 8.1. |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Zitat:
Delphi-Quellcode:
TThread.Synchronize(nil, deineProzedur);
Oder einen ExternalThread erstellen.
Delphi-Quellcode:
gibt dir eine TThread-Instanz für einen fremden/unbekannten Thread. (ich weiß aber nicht seit wann es das in der RTL schon gibt)
TThread.Current
|
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Neues ...
@jaenicke System.TMonitor.Enter/Exit auf irgendeine andere Bitmap als innerhalb der aufrufenden Klasse anzuwenden, geht hier völlig in die Hose. Programmabsturz. Da ich keine Ahnung von der Anwendung dieser Methoden habe und auch nix wirklich gescheites dazu finde, hab ich das erst mal verworfen. Und Zuweisen von Handles von Quell- zu Ziel-Bitmap scheint ohne Release (BM ungültig ?!) auch irgendwie nicht zu funzen. Für jedes Update eine neue BM zu erzeugen ist hier nicht unbedingt erstrebenswert. Betreff Synchronize: Remi Lebeau schrieb im SOF, das NIL als Param das gleiche wäre wie TThread.CurrentThread. Er sollte es wissen. Desweiteren las ich irgendwo, das es angeblich nix anderes (?!) machen soll wie CSLock.Enter/Leave. Hhhmmm. Allerdings: Mit Synchronize(NIL, ...) gibt es hier (sowohl in der o.g. Demo und meinem eigentlichen Proggy) keinen Absturz oder AV's - aber wieder mal bleibt schlicht und ergreifend die Anzeige "irgend wann mal hängen". Der gleiche Effekt, als wenn ich meine Quell-BitMap NICHT mit Assign zuweise, sondern stattdessen Canvas.CpoyRect oder Canvas.Draw probiere. Auf was wird da eigentlich "gesynchronized" ? Auf den Main-Thread/-Form der App ? Falls ja, da will ich doch gar nicht hin .... Ist denn eine extra OSD-Form nicht auch ein weiterer Thread ? Auf die/den will ich aber (aus einem wiederum weiteren Fred / DirectSHow) schreiben .... |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Zitat:
Erzeuge dir doch dazu mal in der OSD-Form ein FormCreate-Eventhandler und schreibe da wie folgt:
Delphi-Quellcode:
PS: Bitte nicht mehr "Fred" für Thread schreiben. Das ist genauso schlimm wie "Schlepptop und Teflon zum Bleistift". :spin2:
if MainThreadID = TThread.Current.ThreadId then
ShowMessage('Ich bin im Hauptthread'!) else ShowMessage('Ich bin in einen anderen Thread Context:' + UIntToStr(TThread.Current.ThreadId)); |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Liste der Anhänge anzeigen (Anzahl: 1)
TThread.Current.ThreadId kennt D2009 nicht, aber TThread.CurrentThread.ThreadId. Schreibfehler oder Tokyo ?
Die aufrufende Methode:
Delphi-Quellcode:
Die empfangende Methode:
procedure TTeletext.ShowTTxt(Mode : boolean; Page : integer);
var ID1, ID2 : cardinal; begin ID1 := MainThreadID; ID2 := GetCurrentThreadId; // TThread.CurrentThread.ThreadId; if ID1 = ID2 then LOG('ShowTTxt', 'Ich bin im Hauptthread') else LOG('ShowTTxt', 'Ich bin in einen anderen Thread Context:' + IntToStr(ID2)); if not Assigned(FOSD) then begin FOSD := TFormOSD.Create(nil); end; FOSD.OSDshow(Mode, FBMOSD); SetPageNumber(Page); FShowTTxt := Mode; end;
Delphi-Quellcode:
Mein LOGGER sagt:
procedure TFormOSD.FormCreate(Sender: TObject);
var ID1, ID2 : cardinal; begin ID1 := MainThreadID; ID2 := GetCurrentThreadId; //TThread.CurrentThread.ThreadId; if ID1 = ID2 then LOG('FormCreate', 'Ich bin im Hauptthread') else LOG('FormCreate', 'Ich bin in einen anderen Thread Context:' + IntToStr(ID2)); ... end;
Code:
Letzteres ist mir völlig unbegreiflich, weil ich das vor ein paar Tagen explizit & ausführlich getest habe und da waren ID1 und ID2 noch unterschiedlich ! ... sonst hätte ich das in den Postings vorher nicht so besimmt geschrieben.
[17:35:53:113] [TTXT - ShowTTxt]: Ich bin im Hauptthread
[17:35:53:116] [OSD - FormCreate]: Ich bin im Hauptthread Desweiteren:
Delphi-Quellcode:
funktioniert - hatte ich dieser Tage auch so.
ID2 := GetCurrentThreadId;
Delphi-Quellcode:
führt beim Beenden des Progs zu einer AV - siehe angehängtes Bild.
ID2 := TThread.CurrentThread.ThreadId;
.... ich versteh die Welt nicht mehr. |
AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Nachtrag: .... die Welt ist doch noch nicht untergegangen. 8-)
Das o.g. noch mal in meine Update-Methode eingebaut:
Delphi-Quellcode:
Dazu sagt der LOGGER (bei jedem Aufruf):
procedure TTeletext.UpdateOSD();
var ID1, ID2 : cardinal; begin ID1 := MainThreadID; ID2 := GetCurrentThreadId; // TThread.CurrentThread.ThreadId; if ID1 = ID2 then LOG('UpdateOSD', 'Ich bin im Hauptthread') else LOG('UpdateOSD', 'Ich bin in einen anderen Thread Context:' + IntToStr(ID2)); if NOT FShowTTxt then exit; if NOT Assigned(FOSD) then exit; FOutputCS.Enter; try FOSD.OSDupdate(FBMOSD); finally FOutputCS.Leave; end; end;
Code:
Aha ! Bin ich also doch nicht völlig verkalkt.
[17:49:36:178] [TTXT - UpdateOSD]: Ich bin in einen anderen Thread Context: 1572
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:24 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz