![]() |
Threads und TBitmaps...schon wieder :-)
Hallo,
das Thema Bitmaps / Threadsicherheit ist hier ja schon öfter aufgetaucht. Hab hier auch diesen Code gefunden der für mich auch funktioniert.
Delphi-Quellcode:
IRPaint wird ja nach dem Zeichnen aufgerufen, klappt alles auch soweit. unit Unit2; interface uses dbgmsgs, Winapi.Windows, SyncObjs, System.Classes, Vcl.Graphics; type TImageRenderer = class(TThread) private fBmp: TBitmap; fOnPaint: TNotifyEvent; procedure PaintBmp; protected procedure Execute; override; public constructor Create; destructor Destroy; override; property OnPaint: TNotifyEvent read fOnPaint write fOnPaint; end; implementation uses Unit1; { ImageRenderer } constructor TImageRenderer.Create; begin inherited Create; fBmp := TBitmap.Create; fBmp.SetSize(100, 100); fBmp.PixelFormat := pf24Bit; end; destructor TImageRenderer.Destroy; begin fBmp.Free; inherited; end; procedure TImageRenderer.Execute; var ix: Integer; iy: Integer; begin while Not Terminated do begin fBmp.Canvas.Lock; for ix := 0 to 99 do begin for iy := 0 to 99 do begin fBmp.Canvas.Pixels[ix,iy] := RGB(Random(256),Random(256),Random(256)); end; Sleep(5); end; fBmp.Canvas.UnLock; Synchronize(PaintBmp); end; end; procedure TImageRenderer.PaintBmp; begin if assigned(fOnPaint) then begin fOnPaint(fBmp); end; end; end. // Formularseite unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Unit2, Vcl.StdCtrls, Vcl.ExtCtrls; type TForm1 = class(TForm) Image1: TImage; Button1: TButton; Label1: TLabel; ICntLbl: TLabel; procedure Button1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); private fRT: TImageRenderer; procedure IRTerminate(Sender: TObject); procedure IRPaint(Sender: TObject); public end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin if Not Assigned(fRT) then begin Image1.Picture.Bitmap.SetSize(200,200); Image1.Picture.Bitmap.Canvas.Brush.Color := RGB(Random(256),Random(256),Random(256)); Image1.Picture.Bitmap.Canvas.FillRect(Rect(0,0,200,200)); fRT := TImageRenderer.Create; fRT.OnTerminate := IRTerminate; fRT.FreeOnTerminate := TRUE; fRT.OnPaint := IRPaint; Button1.Caption := 'Stop'; end else begin fRT.Terminate; Button1.Caption := 'Go'; end; end; procedure TForm1.IRTerminate(Sender: TObject); begin fRT := NIL; end; procedure TForm1.FormDestroy(Sender: TObject); begin if Assigned(fRT) then fRT.Terminate; end; procedure TForm1.IRPaint(Sender: TObject); Var iBmp: TBitmap; begin iBmp := Sender As TBitmap; Image1.Picture.Bitmap.Canvas.Draw(10,10, iBmp); //-------------------------------------------- ICntLbl.Tag := ICntLbl.Tag + 1; ICntLbl.Caption := IntToStr(ICntLbl.Tag); end; end. Nun würde ich gern in der TImageRenderer.Execute eine Schleife laufen lassen die Daten aus verschiedenen Buffern holt und in einen Array of Bitmap zeichnet. Wenn alle 10 Arrays gezeichnet sind IRPaint auslösen und im Mainform einen Array of Bitmap mit den neuen Bitmaps die im Thread gezeichnet wurden füllen. Wie geht man das an ? Pointer auf ein TBitmap Array ? |
AW: Threads und TBitmaps...schon wieder :-)
Zitat:
Du setzt doch eh schon pf24Bit. Das ist wie gemacht für einen Zugriff via TBitmap.Scanline! Wenn Du die Bilder innerhalb des Threads erzeugst würde ich aber ganz auf TBitmap verzichten und lieber mit einem RGB Raster also array of TRGB...(packed record R,G,B:Byte;end) arbeiten. Das geht noch schneller in dem Moment wie du bereit bist ein weiteres Byte zu spenden, egal ob du es brauchst oder nicht. -> TRGBX...(record R,G,B,X:Byte;end) weil dann der Compiler die Zugriffe weiter optimieren kann. |
AW: Threads und TBitmaps...schon wieder :-)
Danke für den Tipp,
Speed ist da relativ wichtig. Das zu zeichnende ist ein Koordinatenhaufen aus X/Y/R/G/B. Also Vektorgrafiken mit 100-500 Punkten. Die im Thread gleich in ein TBitmap zu packen kam mir am einfachstem vor weil ich die Bitmaps ja im Mainthread in die bis zu 40 TImages packen möchte. |
AW: Threads und TBitmaps...schon wieder :-)
Zitat:
|
AW: Threads und TBitmaps...schon wieder :-)
Wenn du schon auf Pixels zugreifen musst, dann TPngimage. Das ist schneller als TBitmap.Canvas. Überhaupt arbeite ich gerne mit TPngimage.
|
AW: Threads und TBitmaps...schon wieder :-)
Hallo,
zum zeichnen brauche ich nur Pen.color, moveto und lineto |
AW: Threads und TBitmaps...schon wieder :-)
Oder Image32
![]() Habs nicht probiert, aber sollte auch im Thread nutzbar sein, wenn man es nicht rendern lässt. |
AW: Threads und TBitmaps...schon wieder :-)
Ich habe die Frage, ob die Verwendung von TBitmap multithreaded auch dann kritisch ist, wenn das Bitmap nur jeweils von einem Thread bearbeitet und ansonsten nicht weiter angefasst wird. Ich erstelle Vorschaubilder aus JPG, speichere sie in einer Liste und zeichne sie bei Bedarf auf einen Canvas.
|
AW: Threads und TBitmaps...schon wieder :-)
Du solltest auf jeden Fall den Kode der mit einem Canvas arbeitet in
Delphi-Quellcode:
einschließen ("Canvas" muss natürlich durch den Bezeichner des Canvas ersetzt werden, den Du da verwendest.)
Canvas.Lock;
try Zeichnen hier finally Canvas.Unlock; end; Die VCL hat eine interne Verwaltung von GDI-Objekten wie Font, Pen, Brush um GDI-Handles zu sparen und die ist nicht thread-safe. Die Lock/Unlock Aufrufe beheben das. |
AW: Threads und TBitmaps...schon wieder :-)
Hallo Peter, vielen Dank für deine Antwort. Die Sachen mit Objekten wie Font, Pen, Brush usw. hatte ich schon mal gehört, und auch, dass
Delphi-Quellcode:
Pflicht ist. Dass es da eine interne Verwaltung von GDI-Objekten gibt, um GDI-Handles zu sparen, erklärt es mir. Es ist natürlich blöd, aber irgendwie wollte ich mich gern um das Lock drücken, weil ich da Geschwindigkeitseinbußen vermutete; habe es allerdings nie nachgemessen. Es kam früher immer wieder mal zu Exceptions beim Einlesen von sehr vielen Bildern und dementsprechender Erstellung von BMP, aber in letzter Zeit nicht mehr. Ist natürlich kein Umgang damit. Ich werde jetzt mal das Lock setzen und auch mal nachmessen, ob das wirklich spürbar Zeit kostet.
Canvas.Lock
|
AW: Threads und TBitmaps...schon wieder :-)
Locks dienen im Gegenteil eher dem Performancegewinn (oder hier eben anderen Zwecken), weil man damit verhindert, dass jemand "von der Seite reingrätscht". Langsamer wird es meistens eher nicht.
|
AW: Threads und TBitmaps...schon wieder :-)
Ich habe jetzt die Locks eingefügt. Ob es dadurch langsamer geworden ist, weiß ich nicht, aber ich habe dadurch den alten Code wieder durchgesehen und dabei eine völlig neue Erfahrung gemacht: Wenn man eine Bitmap freigibt, dann ist es immer gut, wenn man sie vorher erzeugt hat. Erst ein
Delphi-Quellcode:
, dann ein später eingefügtes bedingtes
Create
Delphi-Quellcode:
, danach ein unbedingtes
Exit
Delphi-Quellcode:
- das ist nicht gut, auch ganz ohne multithreaded. Das
Free
Delphi-Quellcode:
hinter das
Create
Delphi-Quellcode:
und weg sind die Exceptions. So einfach kann Programmieren sein.
Exit
|
AW: Threads und TBitmaps...schon wieder :-)
Zitat:
Solange die Variable entweder auf eine Bitmap verweist oder nil ist, ist es kein Problem ein Free aufzurufen, denn das prüft, ob Self <> nil ist. Das Problem ist daher nicht das Free oder ein nicht immer aufgerufenes Create, sondern eine fehlende Initialisierung der Variablen. |
AW: Threads und TBitmaps...schon wieder :-)
Wobei normal der Compiler dann ja auch einen Tipp geben würde, wenn die Variable nicht initialisiert wurde. :stupid:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:33 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