小弟写了一个实现产品类别下载的功能,但是当类别数目很多时,下载的时间要很久,在下载的过程中,不能操作其他模块,以下是我的代码,搞了很久,还是不能并行
unit Uncplbxz;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Unfxks, DB, MemDS, DBAccess, MyAccess, StdCtrls, ExtCtrls,
ComCtrls, ScktComp, AstaCustomSocket, AstaClientSocket, AstaDrv2,
AstaClientDataset,CommCtrl, Grids, DBGrids,TreeUtils,WinInet,ActiveX;type
TFmcplbxz = class(TFmfxks)
AstaClientDataSet1: TAstaClientDataSet;
AstaClientDataSet2: TAstaClientDataSet;
AstaClientDataSet3: TAstaClientDataSet;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure btn1Click(Sender: TObject);
procedure tv1Click(Sender: TObject);
private
{ Private declarations }
procedure AddTree(MyNode : TTreeNode; PData: PNodeData);
public
{ Public declarations }
end; chanpinxiazai = class(tthread)
private
{ Private declarations }
public
constructor Create; virtual; { 线程构造器 }
procedure exteriorwork;
procedure execute;override;
end;var
Fmcplbxz: TFmcplbxz;
thrd:chanpinxiazai;implementation
uses DMFrm,uQsyCommon, uQsyAppUtils,uQsyDBUtils,UnProType1;constructor chanpinxiazai.Create;
begin
inherited Create(True);
FreeOnTerminate := False;
end;procedure chanpinxiazai.exteriorwork;
var
i:Integer;
currNode: TTreeNode;
strsql : string;
amyQuery:tmyquery;
Item: TTVItem;
begin
for i:=0 to Fmcplbxz.tv1.Items.Count -1 do
begin
currNode := Fmcplbxz.tv1.Items.Item[i];
//模块选中
item.mask := TVIF_HANDLE;
item.hItem := currNode.ItemId;
TreeView_GetItem(Fmcplbxz.tv1.Handle, item);
item.mask := TVIF_HANDLE or TVIF_STATE;
if item.state = (item.state or $2000) and (not $1000) then
begin
//0 是根节点
//先查找本地数据,如果已经下载则不再下载
Fmcplbxz.qry.Close;
Fmcplbxz.qry.SQL.Clear;
Fmcplbxz.qry.SQL.Add('select * from T_PROTYPE where t_proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
//Fmcplbxz.qry.Prepared;
Fmcplbxz.qry.Open;
if not Fmcplbxz.qry.IsEmpty then
begin
//类别属性要先删除
amyQuery:=tmyquery.create(nil );
with amyQuery do
try
connection:=Fmcplbxz.qry.Connection;
sql.Clear;
sql.Add('select T_TYPEID from T_ATTRIBUTE where T_PROCLASSID = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
open;
while not eof do
begin
ExecuteSQL(DM.Con,'delete from T_ATTRIBUTE where T_TYPEID = '
+ QuotedStr(fieldbyname('T_TYPEID').AsString));
next;
end;
finally
free;
end;
ExecuteSQL(DM.Con,'delete from T_PROTYPE where t_proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
end;
//开始插入数据
Fmcplbxz.AstaClientDataSet2.Close;
Fmcplbxz.AstaClientDataSet2.SQL.Clear;
Fmcplbxz.AstaClientDataSet2.SQL.Add('select * from T_PROTYPE where proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
Fmcplbxz.AstaClientDataSet2.Open;
strsql := 'INSERT INTO T_PROTYPE (t_proclassid,t_cmpid,t_proclassname,'
+ 'T_PROFCLASSID,T_PROISLAST,T_PROINDEX,T_PROISPUBLIC,T_PROSHOWTYPE'
+ ') VALUES ('
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('proclassid').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('companyID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('proclassname').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROFCLASSID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROISLAST').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROINDEX').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROISPUBLIC').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROSHOWTYPE').AsString)
+ ')';
ExecuteSQL(DM.Con,strsql);
//类别属性也要下载下来
Fmcplbxz.AstaClientDataSet3.Close;
Fmcplbxz.AstaClientDataSet3.SQL.Clear;
Fmcplbxz.AstaClientDataSet3.SQL.Add('select * from t_attribute where proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
Fmcplbxz.AstaClientDataSet3.Open;
while not Fmcplbxz.AstaClientDataSet3.eof do
begin
strsql := '';
strsql := 'INSERT INTO t_attribute (T_TYPEID,T_PROCLASSID,T_PARENTID,'
+ 'T_ATTNAME,T_ATTORDER,T_ATTSTYLE,T_ATTSIGN,t_ATTINDEX'
+ ') VALUES ('
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('TYPEID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('PROCLASSID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('typefclassid').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTNAME').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTORDER').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTSTYLE').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTSIGN').AsString)+ ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTINDEX').AsString)
+ ')';
ExecuteSQL(DM.Con,strsql);
Fmcplbxz.AstaClientDataSet3.next;
end;
end;
end;
FmProType1.ds1.DataSet.Refresh;
FmProType1.ds2.DataSet.Refresh;
FmProType1.FormInit;
end;procedure chanpinxiazai.Execute;
begin
{ Place thread code here }
CoInitialize( nil );
Synchronize(exteriorwork);
showmessage('下载成功!');
end;
{$R *.dfm}
unit Uncplbxz;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Unfxks, DB, MemDS, DBAccess, MyAccess, StdCtrls, ExtCtrls,
ComCtrls, ScktComp, AstaCustomSocket, AstaClientSocket, AstaDrv2,
AstaClientDataset,CommCtrl, Grids, DBGrids,TreeUtils,WinInet,ActiveX;type
TFmcplbxz = class(TFmfxks)
AstaClientDataSet1: TAstaClientDataSet;
AstaClientDataSet2: TAstaClientDataSet;
AstaClientDataSet3: TAstaClientDataSet;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure btn1Click(Sender: TObject);
procedure tv1Click(Sender: TObject);
private
{ Private declarations }
procedure AddTree(MyNode : TTreeNode; PData: PNodeData);
public
{ Public declarations }
end; chanpinxiazai = class(tthread)
private
{ Private declarations }
public
constructor Create; virtual; { 线程构造器 }
procedure exteriorwork;
procedure execute;override;
end;var
Fmcplbxz: TFmcplbxz;
thrd:chanpinxiazai;implementation
uses DMFrm,uQsyCommon, uQsyAppUtils,uQsyDBUtils,UnProType1;constructor chanpinxiazai.Create;
begin
inherited Create(True);
FreeOnTerminate := False;
end;procedure chanpinxiazai.exteriorwork;
var
i:Integer;
currNode: TTreeNode;
strsql : string;
amyQuery:tmyquery;
Item: TTVItem;
begin
for i:=0 to Fmcplbxz.tv1.Items.Count -1 do
begin
currNode := Fmcplbxz.tv1.Items.Item[i];
//模块选中
item.mask := TVIF_HANDLE;
item.hItem := currNode.ItemId;
TreeView_GetItem(Fmcplbxz.tv1.Handle, item);
item.mask := TVIF_HANDLE or TVIF_STATE;
if item.state = (item.state or $2000) and (not $1000) then
begin
//0 是根节点
//先查找本地数据,如果已经下载则不再下载
Fmcplbxz.qry.Close;
Fmcplbxz.qry.SQL.Clear;
Fmcplbxz.qry.SQL.Add('select * from T_PROTYPE where t_proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
//Fmcplbxz.qry.Prepared;
Fmcplbxz.qry.Open;
if not Fmcplbxz.qry.IsEmpty then
begin
//类别属性要先删除
amyQuery:=tmyquery.create(nil );
with amyQuery do
try
connection:=Fmcplbxz.qry.Connection;
sql.Clear;
sql.Add('select T_TYPEID from T_ATTRIBUTE where T_PROCLASSID = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
open;
while not eof do
begin
ExecuteSQL(DM.Con,'delete from T_ATTRIBUTE where T_TYPEID = '
+ QuotedStr(fieldbyname('T_TYPEID').AsString));
next;
end;
finally
free;
end;
ExecuteSQL(DM.Con,'delete from T_PROTYPE where t_proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
end;
//开始插入数据
Fmcplbxz.AstaClientDataSet2.Close;
Fmcplbxz.AstaClientDataSet2.SQL.Clear;
Fmcplbxz.AstaClientDataSet2.SQL.Add('select * from T_PROTYPE where proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
Fmcplbxz.AstaClientDataSet2.Open;
strsql := 'INSERT INTO T_PROTYPE (t_proclassid,t_cmpid,t_proclassname,'
+ 'T_PROFCLASSID,T_PROISLAST,T_PROINDEX,T_PROISPUBLIC,T_PROSHOWTYPE'
+ ') VALUES ('
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('proclassid').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('companyID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('proclassname').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROFCLASSID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROISLAST').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROINDEX').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROISPUBLIC').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet2.fieldbyname('PROSHOWTYPE').AsString)
+ ')';
ExecuteSQL(DM.Con,strsql);
//类别属性也要下载下来
Fmcplbxz.AstaClientDataSet3.Close;
Fmcplbxz.AstaClientDataSet3.SQL.Clear;
Fmcplbxz.AstaClientDataSet3.SQL.Add('select * from t_attribute where proclassid = '
+ QuotedStr(PNodeData(Fmcplbxz.tv1.Items.Item[i].Data)^.Index));
Fmcplbxz.AstaClientDataSet3.Open;
while not Fmcplbxz.AstaClientDataSet3.eof do
begin
strsql := '';
strsql := 'INSERT INTO t_attribute (T_TYPEID,T_PROCLASSID,T_PARENTID,'
+ 'T_ATTNAME,T_ATTORDER,T_ATTSTYLE,T_ATTSIGN,t_ATTINDEX'
+ ') VALUES ('
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('TYPEID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('PROCLASSID').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('typefclassid').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTNAME').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTORDER').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTSTYLE').AsString) + ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTSIGN').AsString)+ ','
+ QuotedStr(Fmcplbxz.AstaClientDataSet3.fieldbyname('ATTINDEX').AsString)
+ ')';
ExecuteSQL(DM.Con,strsql);
Fmcplbxz.AstaClientDataSet3.next;
end;
end;
end;
FmProType1.ds1.DataSet.Refresh;
FmProType1.ds2.DataSet.Refresh;
FmProType1.FormInit;
end;procedure chanpinxiazai.Execute;
begin
{ Place thread code here }
CoInitialize( nil );
Synchronize(exteriorwork);
showmessage('下载成功!');
end;
{$R *.dfm}
var
nNode: TTreeNode;
PNode: PNodeData;
strsql : string;
myAstaClientDataSet : tAstaClientDataSet;
begin strsql := 'select * from T_PROTYPE where profclassid = ' + quotedstr(PData^.Index);
myAstaClientDataSet := tAstaClientDataSet.Create(nil);
myAstaClientDataSet.AstaClientSocket := AstaClientDataSet1.AstaClientSocket;
with myAstaClientDataSet do
try
close;
sql.clear;
sql.Add(strsql);
open;
while Eof = False do
begin
New(PNode);
PNode^.Index := FieldByName('PROCLASSID').AsString;
PNode^.Caption := FieldByName('PROCLASSNAME').AsString;
nNode := tv1.Items.AddChildObject(MyNode, PNode^.Caption, PNode);
nNode.Parent.ImageIndex :=0 ;
nNode.Parent.SelectedIndex := 0;
nNode.ImageIndex := 2;
nNode.SelectedIndex := 3;
AddTree(nNode, PNode);
Next;
end;
nnode.Expand(false);
finally
FreeAndNil(myAstaClientDataSet);;
end;
end;procedure TFmcplbxz.FormCreate(Sender: TObject);
var
Node: TTreeNode;
Ptr: PNodeData;
dw: dword;
begin
inherited; if InternetCheckConnection(PAnsiChar(PAnsiChar(ReadCfg('webip','style'))), 1, 0) then
begin
//if dm.AstaClientSocket1.Active then dm.AstaClientSocket1.Active := Not dm.AstaClientSocket1.Active;
dm.AstaClientSocket1.Active := True;
application.ProcessMessages;
tv1.Items.Clear;
with astaclientdataset2 do
begin
close;
sql.Clear;
sql.Add('select * from T_PROTYPE where proindex = ''_'' order by proindex ');
open;
while not eof do
begin
New(Ptr);
Ptr^.Index := astaclientdataset2.FieldByName('PROCLASSID').AsString;
Ptr^.Caption := astaclientdataset2.FieldByName('PROCLASSNAME').AsString;
Node := tv1.Items.AddChildObject(nil, Ptr^.Caption, Ptr);
Node.ImageIndex := 0;
Node.SelectedIndex := 0;
//AddTree(Node, Ptr);
next;
end;
end;
//TreeView带有CheckBox
dw := GetWindowLong(tv1.Handle, GWL_STYLE);
dw := dw or TVS_CHECKBOXES;
SetWindowLong(tv1.Handle, GWL_STYLE, dw);
end else showmessage('网络未连接!');
end;procedure TFmcplbxz.FormDestroy(Sender: TObject);
begin
//inherited; thrd.Terminate; { 销毁之前终止线程执行 }
thrd.Destroy;
Fmcplbxz := nil;
end;procedure TFmcplbxz.btn2Click(Sender: TObject);
begin
inherited; close;
end;procedure TFmcplbxz.btn1Click(Sender: TObject);
begin
inherited; showmessage('下载需要一定时间,请等待');
thrd := chanpinxiazai.Create;
thrd.execute;
self.Close;
end;
procedure TFmcplbxz.tv1Click(Sender: TObject);
begin
inherited; if tv1.Selected.HasChildren= false then
begin
AddTree(tv1.Selected, tv1.Selected.Data);
tv1.Selected.Expand(true);
if tv1.Selected.HasChildren= true then
NotCheckNode(tv1.Selected);
end;
end;end.
begin
{ Place thread code here }
CoInitialize( nil ); // 这里不对, 要 CoUninitialize 在线程结束
// 这里不对, 去掉大同步
Synchronize(exteriorwork);
变成 exteriorwork; 在函数里面实际要更新显示时再同步, 同步时间要短 showmessage('下载成功!');
end; 另外一个问题是, 你不能共用任何线程外的 ADOConnection, 线程中要另外建立一个 ADOConnection, ADOConnection 本身也会阻卡主线运行ClientDataSet 也是同样不行共用 Connection(socket dcom connection )
你必须在线程中新建立一个 connection, ClientDataSet 用这个 connection 连接 server目前我已知的所有 connection 都阻止主线运行, WebService SOAPConnection 不是正真的实时连接, 这个可以
procedure TForm1.Button1Click(Sender: TObject);
begin
//建线程并立即运行
TTestThread.Create(false);
end;
procedure TTestThread.Execute;
var
i:integer;
begin
{ Place thread code here }
FreeOnTerminate:=True;
for i:=0 to 100000 do begin
if self.Terminated then Break;
Inc(Answer,Round(Abs(Sin(Sqrt(i)))));
Synchronize(GiveAnswer);
end;
end;procedure TTestThread.GiveAnswer;
begin
Form1.Caption:=IntToStr(Answer);
end;
注意线程当中不能ShowMessage
不要用Synchronize
但是要是用了VCL控件,不用Synchronize(exteriorwork)就不运行exteriorwork函数,就会产生假死的但是一定得用VCL控件的话,最好用指针.不用Synchronize
把 ShowMessage 部分放到一个函数中,用 Synchronize 调用这个 Synchronize...Synchronize 早在 delphi5 以后版本就不再是一个可选项了, vcl 大部分地方都会自动进入同步, 所以, 调不调用的倒不是强制, 换句话说, vcl 已经有一大部分是线程安全的了, 保持使用 Synchronize 是一个好习惯, 但也不能什么都Synchronize
比如while GetMessage(Msg,...) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
要该线程退出,就PostThreadMessage(Thread.ThreadID,WM_QUIT,0,0);