为什么创建了线程以后还是不能操作Mainform里面的控件?(50分)

  • 主题发起人 主题发起人 qianwq
  • 开始时间 开始时间
Q

qianwq

Unregistered / Unconfirmed
GUEST, unregistred user!
我要从数据库里面去数据然后生成图表,并把图表保存成jpg格式的图片文件
由于数据比较多,一执行就不能进行其他操作了,所以就做了个线程来执行这部分
可是创建线程以后还是不能进行其他操作,必须要等到线程执行结束以后才可以
这是怎么回事呀!
 
当然,你访问了主线程的vcl东西,所以你不得不同步,同步的意思就是阻塞主线程的运行
你的子线程应该访问自己创建的东西,不要去访问主线程创建的vcl对象
(当然,你访问主线程的integer、float之类的原始数据类型的数据是没问题的)
 
原来是这样
那么Tstrings这种类型的数据可以访问吗?
 
不要随便在线程中直接操作主线程窗体中的界面控件,那样等于同步,这是VCL的机制决定的。
不得已时放在Synchronize中,
我看你最好把你的思路详细写给大家看,实在不好猜你的错误出在哪里的。

 
访问当然能访问,但只要是窗体里面的东东就是VCL组件,
访问它也是会占用Application资源,
如果你确定那么数据在你的次线程中不能改变,那不如将它copy一份到线程对象中,给线
程自己使用得了,这样就不会和Application冲突了
 
Tstrings比如是 TMemo.Lines、TListBox.Items之类就不行
如果是单独的TStringList,你要考虑到如果和主线程一起读就可以,如果一方有写的动作则不行
如果偶尔有写的动作,那么可能你开发的时候怎么试验都说成功的,但是以后客户会反应偶尔有出错
的现象,到时候查实很困难的。如果要出现多个线程可能对它写,那么还是要同步
 
我做的时候是在定义线程的类里面放了些东西,然后在Create里面附值,这样是不是就访问了VCL里面的东西
下面是我的类和create函数的定义,
type
SaveChartToJpg = class(TThread)
private
{ Private declarations }
DBChart:TDBchart;
BDateTime:TDateTime;
EDateTime:TDateTime;
ChtSvPath:string;
ChtPara:integer;
ObjIns:Tstrings;
ObjNm:Tstrings;
AttrID:Tstrings;
Attr:Tstrings;
Attr_C:Tstrings;
AttrLabelNm:Tstrings;
protected
procedure Execute;
override;
public
constructor Create(Suspended:Boolean;TmpDBChart:TDBChart;TmpBDateTime:TDateTime;
TmpEDateTime:TDateTime;TmpChtSvPath:string;TmpChtPara:integer;TmpObjIns:Tstrings;
TmpObjNm,TmpAttrID,TmpAttr,TmpAttr_C,TmpAttrLabelNm:Tstrings);
end;

constructor SaveChartToJpg.Create(Suspended:Boolean;TmpDBChart:TDBChart;TmpBDateTime:TDateTime;
TmpEDateTime:TDateTime;TmpChtSvPath:string;TmpChtPara:integer;TmpObjIns:Tstrings;
TmpObjNm,TmpAttrID,TmpAttr,TmpAttr_C,TmpAttrLabelNm:Tstrings);
begin
inherited Create(Suspended);
DBChart:=TmpDBChart;
BDateTime:=TmpBDateTime;
EDateTime:=TmpBDateTime;
ChtSvPath:=TmpChtSvPath;
ChtPara:=TmpChtPara;
ObjIns:=TStringList.Create;
ObjIns.Text:=TmpObjIns.Text;
ObjNm:=TStringList.Create;
ObjNm.Text:=TmpObjNm.Text;
AttrID:=TStringList.Create;
AttrID.Text:=TmpAttrID.Text;
Attr:=TStringList.Create;
Attr.Text:=TmpAttr.Text;
Attr_C:=TStringList.Create;
Attr_C.Text:=TmpAttr_C.Text;
AttrLabelNm:=TStringList.Create;
AttrLabelNm.Text:=TmpAttrLabelNm.Text;
FreeOnTerminate:=True;
end;
 
要看Execute
 
procedure SaveChartToJpg.Execute;
begin
Synchronize(SaveChart);
end;
SaveChart是这个线程里面的函数,就是对Create里面的那些进行操作
用Synchronize就不能操作Mainform,不用就报错 'Variant is not an array'
 
你用了 DBChart:=TmpDBChart
TmpDBChart是否给释放了?另外他是主线程的东西,比较麻烦
 
TmpDBChart需要释放吗?这不是参数吗?
如果释放的话,是放在OnTerminate函数里面吗?
 
不,我说的是调用者那边,不是被调用者这边
 
学习
顺便提前!
 
好像漏了RESUME,忘记了唤醒线呈吧?
constructor SaveChartToJpg.Create(Suspended:Boolean;TmpDBChart:TDBChart;TmpBDateTime:TDateTime;
TmpEDateTime:TDateTime;TmpChtSvPath:string;TmpChtPara:integer;TmpObjIns:Tstrings;
TmpObjNm,TmpAttrID,TmpAttr,TmpAttr_C,TmpAttrLabelNm:Tstrings);
begin
inherited Create(Suspended);
DBChart:=TmpDBChart;
BDateTime:=TmpBDateTime;
EDateTime:=TmpBDateTime;
ChtSvPath:=TmpChtSvPath;
ChtPara:=TmpChtPara;
ObjIns:=TStringList.Create;
ObjIns.Text:=TmpObjIns.Text;
ObjNm:=TStringList.Create;
ObjNm.Text:=TmpObjNm.Text;
AttrID:=TStringList.Create;
AttrID.Text:=TmpAttrID.Text;
Attr:=TStringList.Create;
Attr.Text:=TmpAttr.Text;
Attr_C:=TStringList.Create;
Attr_C.Text:=TmpAttr_C.Text;
AttrLabelNm:=TStringList.Create;
AttrLabelNm.Text:=TmpAttrLabelNm.Text;
FreeOnTerminate:=True;

RESUME ;//唤醒线呈
end;
 
多谢各位的指点!
 
多人接受答案了。
 
后退
顶部