2015-05-07 54 views
2

我在我的项目中使用了PNGImage库,其中整个GUI由.png图片组成,我在运行时加载到TImage。出于某些目的,我必须动态地创建大量相互类似的组件组。每个组由一些TImages组成,并有一个按钮,让用户可以进入另一个页面,了解更多有关点击项目的详细信息。程序结束时出现PNGImage“访问冲突”错误

我使用的代码:在(1)发生

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错误。奇怪的是,它发生的是完全随机的:错误可能发生在第一次点击或可能不会发生10次点击。如果没有错误发生,F8会让我在PNGImage库里面完成一些工作。然而,当发生错误时,F7/8会立即抛出它,而不会做它必须做的事情。只有当我从dynamicaly创建的对象到静态时,这个问题才会发生。

CPU窗口显示错误在此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. 
+0

调用'免费'是好的。你的代码有缺陷,但我们不能告诉你它是什么。请制作一个MCVE。 –

+2

演示代码(您的MCVE)应该在*问题本身中,而不是在某个场外位置。 –

+0

@ moskito-x nope,我只在项目中使用1个表单 – lolbas

回答

7

你还在释放的TLabel而在其OnClick事件处理程序,Selection_Click这就要求hide_dyn_label()这就要求L.Free。你不能那样做。使用某种延迟破坏,f.ex.与布尔变量FreeDynLabels,您可以检查Application.OnIdle。或者将自定义消息发布到表单。

+0

在我的项目中,当我需要隐藏元素并将它们设置为零时,我能够“修复”错误,将父项设置为零,然后在创建之前释放它们 – lolbas

+0

@lolbas您知道'TLabel'具有'Visible:boolean'属性,你不是吗?但为什么要自由和重新创造,为什么不重复使用'TLabel'呢? –

+0

yeaaa但想法是重新创建它,因为在我的情况下,当用户返回列表时,一些信息可能会改变(在服务器端),所以我不得不重新创建它们以显示更改 – lolbas