1

to speed up painting a bitmap in Delphi XE2, I decided to go the following way

a) Create a eg. 10 x Thread and paint only one layer of the bitmap inside the thread class b) once all threads a finished, merge the bitmaps using the bitblt function layer by layer

I did the following experiemental code

unit Unit_BitmapThread;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Data.DB, Data.Win.ADODB,  ActiveX;



type PaintBitmapThread = class(TThread)

    private

    FBitmap  : TBitmap;
    FConnection : TAdoConnection;
    fserver, fdatabasename, ftablename, fsqlstr : String;
    protected
     procedure Execute; override;
    public
    constructor Create ( bmp_width, bmp_height : Integer; server, databasename, tablename, sqlstr : String; ThreadId : Integer );
    destructor destroy ; override;

end;



type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    FAdoConnection : TAdoConnection;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var    i  : Integer;
    aPaintBitmapThread : PaintBitmapThread;
begin
    for i := 1 to 10 do
         begin
          aPaintBitmapThread :=PaintBitmapThread.Create(100,100,'server','database','table','select *',1);
         end;
end;

{ PaintBitmapThread }

constructor PaintBitmapThread.Create(bmp_width, bmp_height: Integer;
  server, databasename, tablename, sqlstr: String; ThreadId: Integer);
begin
    FBitmap  :=TBitmap.create;
    FConnection :=TAdoConnection.Create(nil);
end;

destructor PaintBitmapThread.destroy;
begin
   FBitmap.Free;
   FConnection.Free;
  inherited;
end;

procedure PaintBitmapThread.Execute;
 var
   ThreadQuery : TADOQuery;
   k : integer;
 begin
   inherited;

   CoInitialize(nil) ; //CoInitialize was not called

   ThreadQuery := TADOQuery.Create(nil) ;
   try
// ADO DB THREAD MUST USE OWN CONNECTION
     ThreadQuery.Connection := FConnection;
//     ThreadQuery.ConnectionString := '????';
//     ThreadQuery.CursorLocation := clUseServer;
//     ThreadQuery.LockType := ltReadOnly;
//     ThreadQuery.CursorType := ctOpenForwardOnly;
     ThreadQuery.SQL.Text := FSQLStr;

//     ThreadQuery.Open;
     while NOT ThreadQuery.Eof and NOT Terminated do
     begin



       //Canvas Does NOT Allow Drawing if not called through Synchronize
       //Synchronize(RefreshCount) ;

       ThreadQuery.Next;
     end;
   finally
     ThreadQuery.Free;
   end;

   CoUninitialize()
end;
end. 

Q : a) How to detect once all 10 painting threads are finished and b) How to access the thread[i] and get the bitmap to the main program (VCL) for merging ?

Best solution would be

if Thread[1] and Thread[2] finished -> newBMP :=  Bitblt( bmp1, bm2);

if also Thread[3]finished -> newBMP :=  Bitblt( newBMP, bm3);
 unit all threads-Bitmaps  are merged
user1769184
  • 1,571
  • 1
  • 19
  • 44
  • 3
    Hard to believe painting is the bottleneck. Look at all that wild db stuff you do. I predict the end result will be slower than serial version. – David Heffernan Jun 17 '14 at 22:26
  • 1
    Well you obviously need to save some sort of reference to the thread. Your code above creates a thread and then completely loses the pointer to that thread when you create the next one. You're also not freeing these threads either, major memory leak. – Jerry Dodge Jun 17 '14 at 22:26
  • shoukld a create a array[0..10] of PaintBitmapThread; – user1769184 Jun 17 '14 at 22:29
  • db processing time < 5 sec, painting time ~ 5 min – user1769184 Jun 17 '14 at 22:30
  • Keep the db stuff in the main thread then. I cannot see any painting code. You can paint to a bitmap quite happily in any thread. – David Heffernan Jun 17 '14 at 22:45
  • 5 minutes??? Are you drawing it pixel by pixel or something? As David says, we can't see your code which does the drawing. – Jerry Dodge Jun 17 '14 at 22:52
  • 2
    5 min? Are you sure your looping records does not cause retrieving data? – Sertac Akyuz Jun 17 '14 at 22:53
  • We don't need to see the painting code, @Jerry. That's not what the question asks about. The question asks how to detect when the threads have finished. Painting is irrelevant to the questions that were asked. So are databases, for that matter. – Rob Kennedy Jun 18 '14 at 03:50
  • @Rob Yes, I know that, but since it was brought up, I thought I'd raise that concern. Hence a comment and not an answer. – Jerry Dodge Jun 18 '14 at 05:06

1 Answers1

4

a) How to detect once all 10 painting threads are finished and b) How to access the thread[i] and get the bitmap to the main program (VCL) for merging?

Add an OnTerminate event handler for each thread. This will execute on the main thread. Merge the bitmaps in this event handler. Because it executes on the main thread, synchronization is taken care of.

If the event handler is a method of the thread class then it can gain access to the thread's private bitmap object.

Alternatively, if you don't want to use the event handler, override DoTerminate and synchronize the merge method from there.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490