动态控件的问题--高分(300分)

  • 主题发起人 sword_liu
  • 开始时间
S

sword_liu

Unregistered / Unconfirmed
GUEST, unregistred user!
用两个控件数组创建了多个报表控件(QRLabel和QRDBText),
单查询是只能是一次性,在查询是就要重新创建(因为我的报表栏位可能不同)

请问如何释放创建出的控件?

我试过以下方法,报错.

var
i:Integer;
begin
for i := 0 to ComponentCount-1 do
begin
if (Components[0] is TQRLabel) then TQRLabel(Components[0]).Free;
if (Components[0] is TQRDBText) then TQRDBText(Components[0]).Free;
end;
end;


var
i:Integer;
begin
for i:=0 to Length(QRLaList) - 1 do
begin
QRTeList.Free;
QRLaList.Free;
end;

请问高手门有没有什么解决的办法?
 
if (Components[0] is TQRLabel) then TQRLabel(Components[0]).Free;
????应该为
if (Components is TQRDBText) then TQRDBText(Components).Free;
 
首先你这段程序有问题,如果不是第一个那么就错了
应该是:
I:=0;
While I<ComponentCount Do
Begin
if Components is TQRLabel Then Components.Free
Else Inc(I)
End;
用For循环是不对的
 
创建时把Owner设为nil
QRLaList := TQRLabel.Create(nil);
 
xianjun: 说得不对,用nil你就不能用Components来访问了
 
察看帮助 RemoveControl方法

This code fragment moves any nonvisual components on the form into a separate data module. Note that the components are removed starting with the last component, so that the unprocessed portion of the Components array does not change.

Note: This code does not save the form or data module to disk after the nonvisual components are moved. If executed at runtime, the effect will not persist.

var

I: Integer;
Temp: TComponent;
begin
for I := ComponentCount - 1 downto 0 do
begin
Temp := Components;
if not (Temp is TControl) then
begin
RemoveComponent(Temp);
DataModule2.InsertComponent(Temp);
end;
end;

end;
 
释放的时候应从后往前
begin
for i := ComponentCount-1 downto 0 do
begin
if (Components[0] is TQRLabel) then TQRLabel(Components[0]).Free;
if (Components[0] is TQRDBText) then TQRDBText(Components[0]).Free;
end;
end;
 
var
i:Integer;
begin
for i := ComponentCount-1 downto 0 do//关键点
begin
if (Components is TQRLabel) then TQRLabel(Components).Free;//你的录入有误
if (Components is TQRDBText) then TQRDBText(Components).Free;;//你的录入有误
end;
end;
给分吧?!
 
TK128: 我说的是他的第二种写法,直接自己记录,不用Componnets属性去访问
 
不好意思,还是报错.
List Index out of bounds(62);

why??
 
我的源码:
==================================
procedure TForm12.CreateReport;
var
i,j,k:Integer;
begin
Count:=Pur_DM1.Pur_ADS2.FieldCount;
SetLength(QRLaList,Count);
SetLength(QRTeList,Count);
for i:=0 to high(QRTeList) do
begin
k:=0;
QRLaList:=TQRLabel.Create(Form12);
if i=0 then
QRLaList.Left:=38
else
QRLaList.Left:=QRLaList[i-1].Left+QRLaList[i-1].Width+12;
QRLaList.Parent:=QuickRep1;
QRLaList.AutoSize:=False;
Pur_DM1.Pur_ADS2.First;
while not Pur_DM1.Pur_ADS2.Eof do
begin
if Pur_DM1.Pur_ADS2.Fields.DataSize>k then
k:=Pur_DM1.Pur_ADS2.Fields.DataSize;
Pur_DM1.Pur_ADS2.Next;
end;
QRLaList.Width:=K*3+20;
QRLaList.Caption:=Pur_DM1.Pur_ADS2.Recordset.Fields.Name;
QRLaList.Top:=130;
QRLaList.Font.Size:=8;
QRTeList:=TQRDBText.Create(Form12);
QRTeList.Parent:=DetailBand1;
QRTeList.DataSet:=Pur_DM1.Pur_ADS2;
QRTeList.DataField:=Pur_DM1.Pur_ADS2.Recordset.Fields.Name;
QRTeList.AutoSize:=True;
QRTeList.Top:=10;
QRTeList.Left:=QRLaList.Left-38;
end;
if Pur_DM1.Pur_ADS2.RecordCount/24<>Pur_DM1.Pur_ADS2.RecordCount div 24 then
QRExpr1.Expression:='''Page ''+'+'PAGENUMBER'+'+'' of ''+'+''''+FloatToStr(Pur_DM1.Pur_ADS2.RecordCount/24-(Pur_DM1.Pur_ADS2.RecordCount / 24-Pur_DM1.Pur_ADS2.RecordCount div 24)+1)+''''
else
QRExpr1.Expression:='''Page ''+'+'PAGENUMBER'+'+'' of ''+'+''''+IntToStr(Pur_DM1.Pur_ADS2.RecordCount div 24)+'''';
ShowMessage(QRExpr1.Expression);
QuickRep1.Preview;
end;


释放的源码是
======================================
procedure TForm12.QuickRep1AfterPreview(Sender: TObject);
var
i:Integer;
Temp:TComponent;
begin
for i := ComponentCount-1 downto 0 do//关键点
begin
if (Components is TQRLabel) then TQRLabel(Components).Free;//你的录入有误
if (Components is TQRDBText) then TQRDBText(Components).Free;;//你的录入有误
end;
end;
============================
一再报错.

 
企盼高手
 
你创建的对象根本不在Components树组中,Components中对象必须用容器的InsertControl
和RemoveControl方法插入和删除。你不能强行管理。QRLaList是一个全局数组,你直接用
语句free。
特别提示。Components中对象,再容器(form)释放的时候,自动释放。否则会出错。
 
把procedure TForm12.QuickRep1AfterPreview(Sender: TObject);中的代码去掉
QRLaList:=TQRLabel.Create(Form12);应该改成QRLaList:=TQRLabel.Create(Self);
每次报表用完后把TForm12的实例Free掉就OK了。
如 with TForm12.Create(Application) do
try
CreateReport; //动态创建控件
ShowModal;
finally
Release; //由于你在创建QRLabel等时指定Self为Owner,故在此时直接被Free掉
end;
 
可是我在使用
procedure TForm12.QuickRep1AfterPreview(Sender: TObject);
var
i:Integer;
begin
for i:=0 to Count do
begin
QRLaList.Free;
QRTeList.Free;
end;
end;
的时候也报错,(内存溢出)
 
for i:=0 to Count do
begin
QRLaList.Free;
QRTeList.Free;
end;
肯定错!只能用 For i:=count-1 downto 0
其实动态创建控件,你可以定义一个
控件列表变量:
var ComponentList:TStringList;
在创建控件时如:
Label1:=TLabel.create(self);
Label1.Name:='Label1';
ComponentList。addobject(Label1.Name,TLabel);
要释放时:
for i:=0 to ComponentList.count-1 do
TLabel(ComponentList).free
ComponentList.free
 
to xianjun
我按你的方法可行,但有一个问题,请问以定要写在with TForm吗?
谢谢
 
用我的写法就是把所有手工创建的控件交给它的Owner,即你的TForm12去Free,这样做的好处
是不用再自己写Free代码,适用于你的TForm12用完就Free的情形, 但如果你的TForm12是
创建好了要多次调用CreateReport; 方法的话,这样做就不大好,虽然最后TForm12释放的
时候都能把手工创建的控件Free掉,但如果CreateReport; 要执行很多次的话,可能会有效
率问题。
with TForm12.Create(Application) do
try
CreateReport; //动态创建控件
ShowModal;
finally
Release; //由于你在创建QRLabel等时指定Self为Owner,故在此时直接被Free掉
end;
你也可以写成这样:
var
AForm: TForm12;
begin
AForm := TForm12.Create(Application);
try
AForm.CreateReport;
AForm.ShowModal;
finally
AForm.Release;
end;
end;
 
>>> sword_liu:
不好意思,修改一下你的源码...

释放的源码是(经过修改)
======================================
procedure TForm12.QuickRep1AfterPreview(Sender: TObject);
var
i:Integer;
Temp:TComponent;
begin
for i := ComponentCount-1 downto 0 do//关键点
begin
if (Components is TQRLabel) then
FreeAndNil(TQRLabel(Components));//修改
if (Components is TQRDBText) then
FreeAndNil(TQRDBText(Components));//修改
end;
end;
你试试看,不过得在Delphi5上才能运行。。。FreeAndNil()在Delphi5才有...
 
顶部