unit BitmapProducerThread;
interface
uses
System.Generics.Collections,
System.Classes,
System.SyncObjs,
Vcl.Graphics;
type
TBitmapParameters =
record
Width : Integer;
Height : Integer;
constructor Create( AWidth, AHeight : Integer );
end;
TBitmapProducerThread =
class( TThread )
private
FEvent : TEvent;
FInputCS : TCriticalSection;
FOutputCS : TCriticalSection;
FInputQueue : TQueue<TBitmapParameters>;
FOutput : TBitmap;
FOnOutputChanged : TNotifyEvent;
procedure SetOutput(
const Value : TBitmap );
procedure SetOnOutputChanged(
const Value : TNotifyEvent );
function GetOnOutputChanged : TNotifyEvent;
procedure DoOutputChanged;
protected
procedure Execute;
override;
procedure TerminatedSet;
override;
function GetBitmapParameter : TBitmapParameters;
procedure DoExecute;
public
constructor Create;
destructor Destroy;
override;
procedure Add( ABitmapParameters : TBitmapParameters );
procedure Get( ABitmap : TBitmap );
property OnOutputChanged : TNotifyEvent
read GetOnOutputChanged
write SetOnOutputChanged;
end;
implementation
{ TBitmapParameters }
constructor TBitmapParameters.Create( AWidth, AHeight : Integer );
begin
Width := AWidth;
Height := AHeight;
end;
{ TBitmapProducerThread }
procedure TBitmapProducerThread.Add( ABitmapParameters : TBitmapParameters );
begin
FInputCS.Enter;
try
FInputQueue.Enqueue( ABitmapParameters );
FEvent.SetEvent;
finally
FInputCS.Leave;
end;
end;
constructor TBitmapProducerThread.Create;
begin
FInputCS := TCriticalSection.Create;
FOutputCS := TCriticalSection.Create;
FEvent := TEvent.Create(
nil, True, False, '
' );
FInputQueue := TQueue<TBitmapParameters>.Create;
FOutput := TBitmap.Create;
inherited Create;
end;
destructor TBitmapProducerThread.Destroy;
begin
inherited;
FInputQueue.Free;
FOutput.Free;
FOutputCS.Free;
FInputCS.Free;
FEvent.Free;
end;
procedure TBitmapProducerThread.DoExecute;
var
LBitmap : TBitmap;
LParams : TBitmapParameters;
LIdx : Integer;
begin
// Parameter aus Queue holen
LParams := GetBitmapParameter;
LBitmap := TBitmap.Create;
try
// Bitmap erstellen
LBitmap.Canvas.Lock;
try
LBitmap.Width := LParams.Width;
LBitmap.Height := LParams.Height;
// 5000 rote Pixel auf ein Bitmap malen
for LIdx := 1
to 5000
do
LBitmap.Canvas.Pixels[Random( LBitmap.Width ), Random( LBitmap.Height )] := clRed;
finally
LBitmap.Canvas.Unlock;
end;
// Bitmap in die Ausgabe schreiben
SetOutput( LBitmap );
finally
LBitmap.Free;
end;
// Benachrichtigen
Synchronize( DoOutputChanged );
end;
procedure TBitmapProducerThread.DoOutputChanged;
var
LEvent : TNotifyEvent;
begin
LEvent := OnOutputChanged;
if Assigned( LEvent )
then
LEvent( Self );
end;
procedure TBitmapProducerThread.Execute;
begin
inherited;
while not Terminated
do
begin
FEvent.WaitFor;
if not Terminated
then
begin
DoExecute;
end;
end;
end;
procedure TBitmapProducerThread.Get( ABitmap : TBitmap );
begin
FOutputCS.Enter;
try
if Assigned( FOutput )
then
ABitmap.Assign( FOutput );
finally
FOutputCS.Leave;
end;
end;
function TBitmapProducerThread.GetBitmapParameter : TBitmapParameters;
begin
FInputCS.Enter;
try
Result := FInputQueue.Dequeue;
if ( FInputQueue.Count = 0 )
and not Terminated
then
FEvent.ResetEvent;
finally
FInputCS.Leave;
end;
end;
function TBitmapProducerThread.GetOnOutputChanged : TNotifyEvent;
begin
FOutputCS.Enter;
try
Result := FOnOutputChanged;
finally
FOutputCS.Leave;
end;
end;
procedure TBitmapProducerThread.SetOnOutputChanged(
const Value : TNotifyEvent );
begin
FOutputCS.Enter;
try
FOnOutputChanged := Value;
finally
FOutputCS.Leave;
end;
end;
procedure TBitmapProducerThread.SetOutput(
const Value : TBitmap );
begin
FOutputCS.Enter;
try
FOutput.Assign( Value );
finally
FOutputCS.Leave;
end;
end;
procedure TBitmapProducerThread.TerminatedSet;
begin
inherited;
FEvent.SetEvent;
end;
end.