如何通过多线程绘制到TBitmap中 [英] How to paint by multi threading into a TBitmap
问题描述
a)创建一个例如。 10 x线程和油漆只有线程类
b内的一层位图)一旦所有线程完成,使用bitblt函数逐层合并位图
我做了以下实验代码
unit Unit_BitmapThread;
接口
使用
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;覆盖
public
构造函数Create(bmp_width,bmp_height:Integer; server,databasename,tablename,sqlstr:String; ThreadId:Integer);
析构函数破坏;覆盖
end;
type
TForm1 = class(TForm)
Button1:TButton;
procedure Button1Click(Sender:TObject);
private
{Private-Deklarationen}
FAdoConnection:TAdoConnection;
public
{public-Deklarationen}
end;
var
Form1:TForm1;
实现
{$ R * .dfm}
程序TForm1.Button1Click(发件人:TObject);
var i:整数;
aPaintBitmapThread:PaintBitmapThread;
begin
for i:= 1 to 10 do
begin
aPaintBitmapThread:= PaintBitmapThread.Create(100,100,'server','database','table','select * ',1);
结束
结束
{PaintBitmapThread}
构造函数PaintBitmapThread.Create(bmp_width,bmp_height:Integer;
server,databasename,tablename,sqlstr:String; ThreadId:Integer);
begin
FBitmap:= TBitmap.create;
FConnection:= TAdoConnection.Create(nil);
结束
析构函数PaintBitmapThread.destroy;
begin
FBitmap.Free;
FConnection.Free;
继承;
结束
程序PaintBitmapThread.Execute;
var
ThreadQuery:TADOQuery;
k:integer;
开始
继承;
CoInitialize(nil); // CoInitialize没有被调用
ThreadQuery:= TADOQuery.Create(nil);
try
// ADO DB THREAD必须使用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不允许绘图,如果不通过同步调用
// Synchronize(RefreshCount);
ThreadQuery.Next;
结束
finally
ThreadQuery.Free;
结束
CoUninitialize()
end;
结束。
问:a)一旦所有10个绘画线程完成并且
b,如何检测)访问线程[i]并获取主程序(VCL)的位图进行合并?
最佳解决方案将是
如果Thread [1]和Thread [2]完成 - > newBMP:= Bitblt(bmp1,bm2);
如果还有Thread [3]完成 - > newBMP:= Bitblt(newBMP,bm3);
单位所有线程 - 位图被合并
a)所有10个绘制线程完成后如何检测b)如何访问线程[i]并获取主程序(VCL)的位图进行合并?
为每个线程添加一个 OnTerminate
事件处理程序。这将在主线程上执行。合并此事件处理程序中的位图。因为它在主线程上执行,所以需要同步。
如果事件处理程序是线程类的方法,那么它可以访问线程的私有位图对象。
或者,如果不想使用事件处理程序,请覆盖 DoTerminate
并同步合并方法那里。
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
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.
这篇关于如何通过多线程绘制到TBitmap中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!