AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Bitmap.Canvas -> Form.Canvas ... nix zu sehen
Thema durchsuchen
Ansicht
Themen-Optionen

Bitmap.Canvas -> Form.Canvas ... nix zu sehen

Ein Thema von TERWI · begonnen am 9. Jul 2018 · letzter Beitrag vom 19. Jul 2018
Antwort Antwort
Seite 5 von 6   « Erste     345 6      
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#41

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 12. Jul 2018, 12:02
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.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.330 Beiträge
 
Delphi 11 Alexandria
 
#42

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 12. Jul 2018, 12:33
Dazu gibt es auch gerade einen aktuellen Blogeintrag.
https://wiert.me/2018/07/11/dont-acc...-to-demo-that/
Dort wird auch ein Beispiel gezeigt, das dem Thema hier sehr ähnlich ist:
Zitat:
Found a simple one.

Create a new VCL program. Drop a TImage on the form. Insert this code:

Delphi-Quellcode:
procedure TForm47.FormCreate(Sender: TObject);
begin
  TThread.CreateAnonymousThread(
  procedure
  begin
    PaintToImage(Image1);
  end).Start;
end;

procedure TForm47.PaintToImage(image: TImage);
begin
  while true do begin
    Image1.Picture.Bitmap := TBitmap.Create;
    Image1.Picture.Bitmap.Free;
  end;
end;
Run in debugger. Instant access violation in the WMPaint handler of the main thread.
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von TERWI
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49626
378 Beiträge
 
Delphi 11 Alexandria
 
#43

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 14. Jul 2018, 10:15
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. in "Threads und TBitmaps" scheint es ja mit BitMap.Assign zu funktionieren (wenn man weiteres beachtet).

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. ä. ?
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.330 Beiträge
 
Delphi 11 Alexandria
 
#44

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 14. Jul 2018, 18:41
Gibt's da nicht irgendeine andere Möglichkeit/Krücke, das zu lösen ? Mittels DIB o. ä. ?
Ich habe doch schon eine einfache Möglichkeit genannt... nimm einfach das Handle statt die ganze Bitmap durch verschiedene Threads zu reichen. Hier eine schnell hingeworfene Demo, nicht schön geschrieben, aber sie zeigt, dass es so geht...
Delphi-Quellcode:
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;
Das komplette Projekt liegt auch im Anhang.
Angehängte Dateien
Dateityp: 7z Bitmap Thread Demo.7z (4,4 KB, 6x aufgerufen)
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
Benutzerbild von TERWI
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49626
378 Beiträge
 
Delphi 11 Alexandria
 
#45

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 17. Jul 2018, 13:19
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:
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;
Zuweisung des Image im OSD:
Delphi-Quellcode:
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;
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.

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.
Angehängte Dateien
Dateityp: zip OSD_Test.zip (275,1 KB, 6x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.114 Beiträge
 
Delphi 12 Athens
 
#46

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 17. Jul 2018, 13:22
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.
TThread.Synchronize(nil, deineProzedur);


Oder einen ExternalThread erstellen.
TThread.Current gibt dir eine TThread-Instanz für einen fremden/unbekannten Thread. (ich weiß aber nicht seit wann es das in der RTL schon gibt)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (17. Jul 2018 um 13:25 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von TERWI
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49626
378 Beiträge
 
Delphi 11 Alexandria
 
#47

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 18. Jul 2018, 15:06
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 ....
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#48

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 18. Jul 2018, 15:29
Ist denn eine extra OSD-Form nicht auch ein weiterer Thread ? Auf die/den will ich aber (aus einem wiederum weiteren Fred / DirectSHow) schreiben ....
Nein!
Erzeuge dir doch dazu mal in der OSD-Form ein FormCreate-Eventhandler und schreibe da wie folgt:

Delphi-Quellcode:
if MainThreadID = TThread.Current.ThreadId then
  ShowMessage('Ich bin im Hauptthread'!)
else
  ShowMessage('Ich bin in einen anderen Thread Context:' + UIntToStr(TThread.Current.ThreadId));
PS: Bitte nicht mehr "Fred" für Thread schreiben. Das ist genauso schlimm wie "Schlepptop und Teflon zum Bleistift".
  Mit Zitat antworten Zitat
Benutzerbild von TERWI
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49626
378 Beiträge
 
Delphi 11 Alexandria
 
#49

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 18. Jul 2018, 16:47
TThread.Current.ThreadId kennt D2009 nicht, aber TThread.CurrentThread.ThreadId. Schreibfehler oder Tokyo ?

Die aufrufende Methode:
Delphi-Quellcode:
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;
Die empfangende Methode:
Delphi-Quellcode:
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;
Mein LOGGER sagt:
Code:
[17:35:53:113] [TTXT - ShowTTxt]: Ich bin im Hauptthread
[17:35:53:116] [OSD - FormCreate]: Ich bin im Hauptthread
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.

Desweiteren:
ID2 := GetCurrentThreadId; funktioniert - hatte ich dieser Tage auch so.
ID2 := TThread.CurrentThread.ThreadId; führt beim Beenden des Progs zu einer AV - siehe angehängtes Bild.

.... ich versteh die Welt nicht mehr.
Miniaturansicht angehängter Grafiken
thread_err.jpg  
  Mit Zitat antworten Zitat
Benutzerbild von TERWI
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49626
378 Beiträge
 
Delphi 11 Alexandria
 
#50

AW: Bitmap.Canvas -> Form.Canvas ... nix zu sehen

  Alt 18. Jul 2018, 16:56
Nachtrag: .... die Welt ist doch noch nicht untergegangen.
Das o.g. noch mal in meine Update-Methode eingebaut:
Delphi-Quellcode:
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;
Dazu sagt der LOGGER (bei jedem Aufruf):
Code:
[17:49:36:178] [TTXT - UpdateOSD]: Ich bin in einen anderen Thread Context: 1572
Aha ! Bin ich also doch nicht völlig verkalkt.

Geändert von TERWI (18. Jul 2018 um 16:59 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 5 von 6   « Erste     345 6      

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:03 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