主题:谁能帮忙看下这个错误是怎么回事
punkrocker
[专家分:720] 发布于 2007-08-06 21:02:00
简介:
窗体上有一个panel,有一个button(btn1)。
点击btn1后,在panel中生成10个image,10个speedbutton
speedbutton点击后消失(free掉的),露出底下的image。
问题:
speedbutton点击后,总有一个会报错,而且不同机器上报错的位置不同。
我自己机器上是左起第六个报错,同事机器有的是第六个有的是第五个
另外,本来窗体上有2个edit(没用到的),删除这2个edit后,再测试我的机器上变成第九个报错了。。。
代码如下,最好是直接下载附件看unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
pnlArea: TPanel;
btn1: TButton;
procedure btn1Click(Sender: TObject);
procedure btnallclick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btn1Click(Sender: TObject);
var
buttonArea:TSpeedButton;
ImgArea:TImage;
i:integer;
begin
for i:=1 to 10 do
begin
ImgArea:=TImage.create(Form1);
ImgArea.Parent:=pnlArea;
ImgArea.Top:=0;
ImgArea.Left:=23*i;
ImgArea.Name:='Img'+inttostr(i+1);
TImage(ImgArea).Picture.LoadFromFile('.\source\1.bmp');
buttonArea:=TSpeedbutton.create(Form1);
buttonArea.Parent:=pnlArea;
buttonArea.Top:=0;
buttonArea.Left:=23*i;
buttonArea.Name:='btn'+inttostr(i+1);
buttonArea.OnClick:=btnallclick;
end;
end;
procedure TForm1.btnallclick(Sender: TObject);
begin
// TSpeedButton(sender).Glyph.LoadFromFile('.\source\1.bmp');
TSpeedButton(Sender).Free;
end;
end.
回复列表 (共12个回复)
沙发
长尾兔 [专家分:3630] 发布于 2007-08-06 21:39:00
根据你的代码改的,看一下是否合适:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, ExtCtrls, StdCtrls;
type
TForm1 = class(TForm)
pnlArea: TPanel;
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMySpeedBtn = class(TSpeedButton)
public
procedure Free2(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btn1Click(Sender: TObject);
var
ImgArea:TImage;
i:integer;
begin
for i:=1 to 10 do
begin
ImgArea:=TImage.create(Form1);
ImgArea.Parent:=pnlArea;
ImgArea.Top:=0;
ImgArea.Left:=23*i;
ImgArea.Name:='Img'+inttostr(i+1);
TImage(ImgArea).Picture.LoadFromFile('.\source\1.bmp');
with TMySpeedBtn.Create(Self) do begin
Parent:=pnlArea;
Top:=0;
Left:=23*i;
//Name:='btn'+inttostr(i+1);//此句有亦可无亦可
OnClick := Free2;
end;
end;
end;
{ TMySpeedBtn }
procedure TMySpeedBtn.Free2(Sender: TObject);
begin
Self.Free;
end;
end.
板凳
长尾兔 [专家分:3630] 发布于 2007-08-06 21:41:00
需要指出的是,你的代码中,SpeedButton的OnClick事件的处理过程是TForm1的一个方法-----这样的话,两个“类”的藕合程度太高了..
3 楼
长尾兔 [专家分:3630] 发布于 2007-08-06 21:44:00
当然,上面说的不是问题的主要原因。原因是什么,我也在晕中.....好象单独把Name的赋值那句注释掉就行了.....
4 楼
punkrocker [专家分:720] 发布于 2007-08-06 21:45:00
我这种写法问题出在哪?
为什么不同机器出错的按钮不一样?
而且每次是固定位置的按钮出错,如果是每按N个按钮出错我还容易理解点。。
5 楼
长尾兔 [专家分:3630] 发布于 2007-08-06 21:47:00
另外,要注意我代码中使用了无名对象,也就是 with TObject.Create do...这样的用法。你仔细想一下,在一个循环中,反复执行buttonArea:=TSpeedbutton.create(Form1);这句是不是在编程上就是讲不能的?(没Free就Create,幸亏该对象在栈上)
6 楼
punkrocker [专家分:720] 发布于 2007-08-06 21:59:00
我的BTN1是为了测试方便
实际使用的时候这个应该是些在formcreate里的,所以应该不存在未free就create的情况吧
7 楼
长尾兔 [专家分:3630] 发布于 2007-08-06 22:07:00
放在TForm1.FormCreate里和放在TForm1.Button1.OnClick里是一样的。
这个问题有点复杂,暂时没时间思考了,以后我会关注的。希望大家一起讨论。
先下了。
8 楼
xiaohongna [专家分:180] 发布于 2007-08-07 09:13:00
[quote]另外,要注意我代码中使用了无名对象,也就是 with TObject.Create do...这样的用法。你仔细想一下,在一个循环中,反复执行buttonArea:=TSpeedbutton.create(Form1);这句是不是在编程上就是讲不能的?(没Free就Create,幸亏该对象在栈上)[/quote]
首先说明一点~~Delphi里面对象不是在栈上分配的。最明显的是必须先创建对象才能使用。声明一个buttonArea仅仅是一个指针,栈上也就分配了这个指针的内存,至于这个指针指向什么东西就要看那个create了~~
楼主的代码写的的确奇怪,但是也不能说就是错误的(以我现在看来);楼主个猪,等我想想~~~
9 楼
xiaohongna [专家分:180] 发布于 2007-08-07 09:52:00
Punk拜我为师吧~~
1:click事件是在Tcontrol里面声明的~~给你看看重要部分的代码
..............
if PtInRect(ClientRect, SmallPointToPoint(Message.Pos)) then Click;
end;
DoMouseUp(Message, mbLeft);
看好~~~当执行完Click以后对象还会调用DomouseUP()过程, 而你在click里面就把这个对象释放了。你可以继续跟踪 它会访问FOnMouseUp 这个私有字段,这个是要在对象所在的堆里面占内存的。
2:为什么会报不同的内存地址错误,这个就比较复杂了,完全和内存分配有关,不同的情况就会分配不同的地址~~
总之,在onclick里面释放本身是不对的~~事件并不一定是一个过程的末端。
10 楼
xiaohongna [专家分:180] 发布于 2007-08-07 09:59:00
对了 没有给你说如何解决。
非常简单,设置它Visible就行了~~
另外一点 ImgArea:=TImage.create(Form1); 最好写成 ImgArea:=TImage.create(self); 里面也不用担心内存泄露,Tcomponent会自动管理的。
扫雷不是这样做的,应该完全用Tcanvas画出来。那个数字更不是用的图片,Textout画出来的。
我来回复