1

我创建了一个自定义 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;  
4

2 回答 2

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;

AFAICTApplication.ProcessMessages是不需要的。

于 2012-08-09T06:08:10.647 回答
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; 
于 2012-08-09T09:32:31.157 回答