PNGImage "Access violation" 过程结束时出错
PNGImage "Access violation" error at procedure end
我在我的项目中使用 PNGImage 库,整个 GUI 由 .png 图像组成,我在 运行 时加载到 TImages。出于某些目的,我必须动态创建大量彼此相似的组件组。每个组都包含一些 TImages 并有一个按钮,让用户可以继续到另一个页面,其中包含有关单击项目的更多详细信息。
我使用的代码:
procedure TMain_Frame.selection_click(Sender: TObject);
var id: string;
begin
id := StringReplace(TLabel(sender).Name, 'label_item_select_', '', [rfReplaceAll]);
hide_created_components; // It does Free all components
show_details(id);
end; // (1)
Access violation
错误发生在 (1)
。奇怪的是,它的发生完全是随机的:错误可能在第一次点击时发生,也可能在 10 次点击后都没有发生。如果没有发生错误,F8 会引导我进入 PNGImage 库,其中一些东西已经完成。但是,当发生错误时,F7/8 会立即抛出它,而不做它必须做的事情。仅当我从动态创建的对象变为静态时才会出现此问题。
CPU window 表明错误发生在这个 ASM 代码处:
movzx ecx, [edi]
ecx值为755A2E09,edi为00000000
.Free
所有动态创建的组件是否正确?或者应该使用 .Destroy
代替?为什么 PNGImage 在过程 end;
中进入自身内部?
演示:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, pngimage, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
procedure selection_click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure create_label;
var Button: TLabel;
begin
Button := TLabel.Create(Form1);
with Button do
begin
Name := 'dynamic_label_1';
Parent := Form1;
Autosize := false;
Left := 100;
Top := 100;
Width := 150;
Height := 20;
Caption := 'Dynamic Label: Click Me';
BringToFront;
Cursor := crHandPoint;
end;
Button.OnClick := Form1.selection_click;
end;
procedure hide_dyn_label(L: TLabel; mode: boolean);
begin
if mode then
begin
L.Free;
Form1.Image1.Picture.LoadFromFile(PAnsiChar('button_close.png'));
Form1.Image1.Visible := true;
end
else
create_label;
end;
procedure TForm1.selection_click(Sender: TObject);
var id: string;
begin
id := StringReplace(TLabel(Sender).Name, 'dynamic_label_', '', [rfReplaceAll]);
Form1.Button1.Visible := true;
hide_dyn_label(Form1.FindComponent('dynamic_label_1') as TLabel, true);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
create_label;
Form1.Image1.Visible := false;
Form1.Button1.Visible := false;
end;
end.
您正在释放 TLabel
,同时仍在其 OnClick
事件处理程序中,Selection_Click
调用 hide_dyn_label()
,后者调用 L.Free
。你不能那样做。使用某种延迟销毁,f.ex。使用布尔变量 FreeDynLabels
,您可以在 Application.OnIdle
中签入。或者 post 向表单发送自定义消息。
我在我的项目中使用 PNGImage 库,整个 GUI 由 .png 图像组成,我在 运行 时加载到 TImages。出于某些目的,我必须动态创建大量彼此相似的组件组。每个组都包含一些 TImages 并有一个按钮,让用户可以继续到另一个页面,其中包含有关单击项目的更多详细信息。
我使用的代码:
procedure TMain_Frame.selection_click(Sender: TObject);
var id: string;
begin
id := StringReplace(TLabel(sender).Name, 'label_item_select_', '', [rfReplaceAll]);
hide_created_components; // It does Free all components
show_details(id);
end; // (1)
Access violation
错误发生在 (1)
。奇怪的是,它的发生完全是随机的:错误可能在第一次点击时发生,也可能在 10 次点击后都没有发生。如果没有发生错误,F8 会引导我进入 PNGImage 库,其中一些东西已经完成。但是,当发生错误时,F7/8 会立即抛出它,而不做它必须做的事情。仅当我从动态创建的对象变为静态时才会出现此问题。
CPU window 表明错误发生在这个 ASM 代码处:
movzx ecx, [edi]
ecx值为755A2E09,edi为00000000
.Free
所有动态创建的组件是否正确?或者应该使用 .Destroy
代替?为什么 PNGImage 在过程 end;
中进入自身内部?
演示:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, pngimage, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
procedure selection_click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure create_label;
var Button: TLabel;
begin
Button := TLabel.Create(Form1);
with Button do
begin
Name := 'dynamic_label_1';
Parent := Form1;
Autosize := false;
Left := 100;
Top := 100;
Width := 150;
Height := 20;
Caption := 'Dynamic Label: Click Me';
BringToFront;
Cursor := crHandPoint;
end;
Button.OnClick := Form1.selection_click;
end;
procedure hide_dyn_label(L: TLabel; mode: boolean);
begin
if mode then
begin
L.Free;
Form1.Image1.Picture.LoadFromFile(PAnsiChar('button_close.png'));
Form1.Image1.Visible := true;
end
else
create_label;
end;
procedure TForm1.selection_click(Sender: TObject);
var id: string;
begin
id := StringReplace(TLabel(Sender).Name, 'dynamic_label_', '', [rfReplaceAll]);
Form1.Button1.Visible := true;
hide_dyn_label(Form1.FindComponent('dynamic_label_1') as TLabel, true);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
create_label;
Form1.Image1.Visible := false;
Form1.Button1.Visible := false;
end;
end.
您正在释放 TLabel
,同时仍在其 OnClick
事件处理程序中,Selection_Click
调用 hide_dyn_label()
,后者调用 L.Free
。你不能那样做。使用某种延迟销毁,f.ex。使用布尔变量 FreeDynLabels
,您可以在 Application.OnIdle
中签入。或者 post 向表单发送自定义消息。