2012-08-09 77 views
1

我創建一個自定義Tpanel我在內心裏把各種自定義組件一TbitBtn ...我怎麼能釋放一個Tpanel這有一個調用來釋放Tpanel

procedure Panel_Comp(Location: TWinControl; NumOfComp:  Integer;Left,Top,Height,width:Integer); 
begin 
    MyPanel := TsPanel.Create(Conf); 
    MyPanel.Name := 'MyPanel' + IntToStr(NumOfComp); 
    MyPanel.Parent := Location; 
    MyPanel.Left := Left; 
    MyPanel.Top := Top; 
    MyPanel.Height := Height; 
    MyPanel.Width := width; 
    MyPanel.Caption := ''; 
end; 

和我這樣稱呼它

Panel_Comp(Conf.ScrollBox1,1,8,10,70,322); 
在相同的邏輯我把新的面板的其它自定義組件內側包括一個tBitbtn的具有onclick事件

..

procedure BitBtn_Comp(Location: TWinControl; NumOfComp: Integer; Left,Top,Height,Width,ImageNum: Integer); 
begin 
    MyBitBtn := TBitBtn.Create(Conf); 
    ...... 
    MyBitBtn.tag := NumOfComp; 
    MyBitBtn.OnClick:= Conf.CloseCurrentPanel; 
end; 

主要Forn TConf.CloseCurrentPanel;

procedure TConf.CloseCurrentPanel(Sender: TObject); 
var 
    panelComp: TComponent; 
begin 
    panelComp := FindComponentEx('Conf.MyPanel'+ IntToStr(TBitBtn(Sender).tag); 
    TPanel(panelComp).Free; 
    Application.ProcessMessages; 
end; 

當我打電話,我得到的訪問衝突...... 我想的東西,我必須在自由的面板釋放面板裏面的所有組件,但我怎麼面板之前釋放BitBtn並繼續行動點擊事件?

這裏是FindComponetEx功能,而不是你需要它...

function FindComponentEx(const Name: string): TComponent; 
var 
    FormName: string; 
    CompName: string; 
    P: Integer; 
    Found: Boolean; 
    Form: TForm; 
    I: Integer; 
begin 
// Split up in a valid form and a valid component name 
    P := Pos('.', Name); 
    if P = 0 then 
    begin 
    raise Exception.Create('No valid form name given'); 
    end; 
    FormName := Copy(Name, 1, P - 1); 
    CompName := Copy(Name, P + 1, High(Integer)); 
    Found := False;  
    // find the form 
    for I := 0 to Screen.FormCount - 1 do 
    begin 
     Form := Screen.Forms[I]; 
    // case insensitive comparing 
     if AnsiSameText(Form.Name, FormName) then 
     begin 
      Found := True; 
      Break; 
     end; 
    end; 
    if Found then 
    begin 
     for I := 0 to Form.ComponentCount - 1 do 
     begin 
      Result := Form.Components[I]; 
     if AnsiSameText(Result.Name, CompName) then Exit; 
     end; 
    end; 
    Result := nil; 
end; 

回答

3

的AV發生,因爲你是摧毀一個組件(MyBitBtn),而它仍然是處理Windows消息。解決的辦法是通過PostMessage,與此類似,直到後來推遲破壞:

unit Unit1; 

interface 

uses 
    Windows, 
    Messages, 
    SysUtils, 
    Variants, 
    Classes, 
    Graphics, 
    Controls, 
    Forms, 
    Dialogs, 
    ExtCtrls, 
    StdCtrls; 

const 
    UM_DESTROYPANEL = WM_APP + 623; // some "unique" number; UM = user message 

type 
    TConf = class(TForm) 
    Panel1: TPanel; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    strict private 
    procedure UMDestroyPanel(var Message: TMessage); message UM_DESTROYPANEL; 
    public 
    { Public-Deklarationen } 
    end; 

var 
    Conf: TConf; 

implementation 

{$R *.dfm} 

procedure TConf.Button1Click(Sender: TObject); 
begin 
    PostMessage(Handle, UM_DESTROYPANEL, 0, 0); 
end; 

procedure TConf.UMDestroyPanel(var Message: TMessage); 
begin 
    Panel1.Free; 
end; 

end. 

如果需要,您可以使用wParam和lParam通過參數傳遞,像這樣:

procedure TConf.Button1Click(Sender: TObject); 
begin 
    PostMessage(Handle, UM_DESTROYPANEL, WPARAM(Panel1), 0); 
end; 

procedure TConf.UMDestroyPanel(var Message: TMessage); 
begin 
    TObject(Message.WParam).Free; 
end; 

編輯: 在你的情況下,我可能會重寫TConf.CloseCurrentPanel像這樣:

procedure TConf.CloseCurrentPanel(Sender: TObject); 
var 
    panelComp: TComponent; 
begin 
    panelComp := FindComponentEx('Conf.MyPanel'+ IntToStr(TBitBtn(Sender).Tag); 
    PostMessage(Handle, UM_DESTROYPANEL, WPARAM(panelComp), 0); 
end; 

您也可以通過標籤(可能是更好的解決方案,因爲有涉及欠鑄):

procedure TConf.CloseCurrentPanel(Sender: TObject); 
begin 
    PostMessage(Handle, UM_DESTROYPANEL, TBitBtn(Sender).Tag, 0); 
end; 

procedure TConf.UMDestroyPanel(var Message: TMessage); 
var 
    panelComp: TComponent; 
begin 
    panelComp := FindComponentEx('Conf.MyPanel'+ IntToStr(Message.WParam)); 
    panelComp.Free; 
end; 

AFAICT的Application.ProcessMessages是沒有必要的。

+0

謝謝你這個很好的作品.... – azrael11 2012-08-10 01:07:24

+0

還有一個關於這個問題...不是開始另一個話題。你能告訴我如何使用我的FindComponentEx找到特定的面板,所以我可以通過wParam或lParam刪除它...謝謝 – azrael11 2012-08-10 01:08:20

+0

這很好...再次感謝您的幫助... – azrael11 2012-08-12 00:35:48

0
procedure TConf.CloseCurrentPanel(Sender: TObject); 
var  
    panelComp: TComponent; 
begin  
    panelComp := FindComponentEx('Conf.MyPanel'+ IntToStr(TBitBtn(Sender).tag); 
    //Where you need to determine 'PanelComp' if there are. 
    if Assigned(panelComp) and (PanelComp is TPanel) then 
    TPanel(panelComp).Free; 
    Application.ProcessMessages; 
end; 
+0

此代碼導致相同違反訪問錯誤... – azrael11 2012-08-10 01:06:29

+0

如果FindComponentEx函數是查找正確的組件,則可以檢查你的TsPanel.Destroy裏面的內容。要進行斷點調試將更容易發現問題。 – 2012-08-13 08:48:40