AGB  ·  Datenschutz  ·  Impressum  







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

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

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

Registriert seit: 16. Jan 2004
Ort: Bendorf
4.770 Beiträge
 
Delphi 2010 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
Online

Registriert seit: 10. Jun 2003
Ort: Berlin
6.851 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#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
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49565
221 Beiträge
 
Delphi 2009 Professional
 
#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
Online

Registriert seit: 10. Jun 2003
Ort: Berlin
6.851 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#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, 2x aufgerufen)
Sebastian Jänicke
Alle eigenen Projekte sind eingestellt, ebenso meine Homepage, Downloadlinks usw. im Forum bleiben aktiv!
  Mit Zitat antworten Zitat
TERWI

Registriert seit: 29. Mär 2008
Ort: D-49565
221 Beiträge
 
Delphi 2009 Professional
 
#45

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

  Alt Heute, 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, 3x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
34.637 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#46

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

  Alt Heute, 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.
Delphi-Tage 2005-2014

Geändert von himitsu (Heute um 13:25 Uhr)
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 16:29 Uhr.
Powered by vBulletin® Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2018 by Daniel R. Wolf