2012-08-09 73 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