动态生成组件时遇到的问题(60分)

  • 主题发起人 主题发起人 W1979
  • 开始时间 开始时间
W

W1979

Unregistered / Unconfirmed
GUEST, unregistred user!
请教个小问题
我有一个动态生成的报表,连接一个动态的SQL,有几个中间变量

List:TstringList, //存放query的字段标题,用于向数组AutoLabel中填充
AutoLabel:array of TQRLabel, //是QuickReport报表的表头
AutoText:array of TQRDBText //是报表的细节

报表的生成放在一个过程中,这样大家都能调用...
问题出现了,Query1调用了这个过程,然后Query2再调时,Query1
中的字段会印在Query2的空白处。我已在窗体的OnClose中加入

List.free;
for i:=0 to....
begin
AutoLabel:=nil;
AutoText:=nil;
end;

无济于事.我该怎么办?

 
List.free;
for i:=0 to....
begin
AutoLabel:=nil; //不能直接设为nil,要<B>释放</B>该对象
AutoText:=nil; //同上
end;
 
你是指AutoLabel.free吗,我就是因为这样有访问冲突才改用
AutoLabel:=nil的.
不知Nil,free,destroy都有什么区别?
 
我仔细检查了程序,很奇怪,数组元素的parent属性设的是QuickReport
的那个form,那么窗体关闭时它们会自动释放,所以我再释放就有访问冲突,
但预览的图象重叠又说明数组没有释放。。。我弄湖涂了:<
 
只要是你自己调用 .create 的, 都要用 .free 来释放,
中间重新赋值可以,但最终一定要释放。
 
我试了一下用你的方法没问题啊!
不如你试试这样:
把parent属性设为NIL;
以后再 FREE
 
重写了一个简化的程序:
多次预览时,前一次的会重叠在上面,显示有东西没有释放。。。

public
count:integer;
list:Tstringlist; //放字段名
autoLabel:array of TQRLabel; //放待生成的组件
autoText:array of TQRDBText;

procedure showAll(var data:TQuery);///调用该过程,显示报表
{ Public declarations }
end;

var
Form1: TForm1;
temp:Tquery;

implementation
uses unit2;

{$R *.DFM}
procedure Tform1.showAll(var data:Tquery);//showAll过程

var i:integer;

begin
count:=data.FieldCount;//字段数目
with form2 do begin
QuickRep1.DataSet:=data;
setlength(autolabel,count+1);
setlength(autoText,count+1);

list:=TstringList.Create;
data.GetFieldNames(list); //获取字段名列表
QRLabel1.Caption:=list[0];

autolabel[1]:=QRLabel1; //QRLabel1,QRtext1已经存在,
autoText[1]:=QRDBText1; // 以提供基准位置
autoText[1].dataset:=data;
autoText[1].datafield:=list[0];
for i:=2 to count do begin //循环赋值
autolabel:=TQRLabel.create(form2.QRBand2);
autolabel.caption:=list[i-1];
autolabel.parent:=form2.QRBand2;
autolabel.left:=autolabel[i-1].left +120;
autolabel.top:=autolabel[i-1].top;
autoText:=TQRDBText.Create(form2.QRBand1);
autoText.datafield:=list[i-1];
autoText.dataset:=autoText[i-1].dataset;
autoText.parent:=form2.QRBand1;
autoText.left:=autoText[i-1].left +120;
autoText.top:=autoText[i-1].top;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);

begin
temp:=query1;
showAll(temp); //调showAll预览
form2.quickrep1.Preview;
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
temp:=query2;
showAll(temp);
form2.QuickRep1.Preview;//调showAll预览
end;

procedure TForm1.Button3Click(Sender: TObject);//释放
var k:integer;
begin
list.Free; //释放后依旧出现字段重叠???????????????
for k:=2 to count do begin
autolabel[k].caption:='';
autoLabel[k].free;
autoText[k].free;
end;


end;

end.
 
是qrBand没有free
 
to automn:
我的Band不是自动生成的,是否有必要free?
如果free,下次还要生成好麻烦的说
 
错了。不是qrband,是qrLabel


autolabel:=TQRLabel.create(form2.QRBand2);
//这里create了,后面的释放没有做好!

...
 
我也觉的奇怪,如上,我明明把数组的元素都释放了(除
了第一个元素,因为那是我设计时放的QR上做基准的)
 
搞错了
是CREATE时用NIL做参数;
以后再 FREE ;
应该就可以了。

因为FREE实际上是DESTROY对对象的内存地址不会做任何修改
所以在FREE后你去测试该地址会发现它仍然有效

实际上FREE时它会先判断对象引用是不是NIL
IF NOT NIL
会假定对象仍然存在,使用对象引用为它分配内存,
然后调用DESTROY释放对象内存,并清除任何相关的虚拟
对象方法的数据表格信息。
所以你两次释放就有问题了(1:宿主做的,2:你做的)


 
for i:=2 to count do
begin //循环赋值
autolabel:=TQRLabel.create(NIL); //修改处
autolabel.caption:=list[i-1];
autolabel.parent:=form2.QRBand2;
autolabel.left:=autolabel[i-1].left +120;
autolabel.top:=autolabel[i-1].top;
autoText:=TQRDBText.Create(form2.QRBand1);
autoText.datafield:=list[i-1];
autoText.dataset:=autoText[i-1].dataset;
autoText.parent:=form2.QRBand1;
autoText.left:=autoText[i-1].left +120;
autoText.top:=autoText[i-1].top;
end;
以后再释放应该可以了
希望有用:)
 
create(nil)后,预览重叠现象消失。
我以前的理解是,create的参数是谁,谁就有义务在自身关闭时释放
它,当create的参数是nil时,才必须显式的调用free.因此我的程序中
写了autolabel:=TQRLabel.create(form6.qrBand1),并以为它能在预
览窗体关闭时自行释放。失败后,我又显式的调用了autolabel.free,
为什么这样都没有将它释放掉?
yxyyyy,我对你的解释还有点不懂
 
Create(...) 缺省的参数是 aOwner,
关于 Owner 现在有时候我也犯糊涂,
不管怎么样,只要你调用 .create, 都得手工 .free

否则不是出错, 就会有内存泄露。

也不知道我说的对不对,欢迎讨论。
 
多人接受答案了。
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
900
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部