2015-05-07 51 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