windows - 我怎样才能释放一个 Tpanel 有一个 TbitBtn 调用释放 Tpanel

标签 windows delphi components delphi-7

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

按照相同的逻辑,我在新面板中放入了其他自定义组件,包括具有 onclick 事件的 tBitbtn。

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;

在主窗体中的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;  

最佳答案

出现 AV 是因为您正在破坏仍在处理 Windows 消息的组件 (MyBitBtn)。解决方案是通过 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

关于windows - 我怎样才能释放一个 Tpanel 有一个 TbitBtn 调用释放 Tpanel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11877394/

相关文章:

windows - 如何获取映射网络驱动器的驱动器号

c++ - msys2 和 header 在 'wrong' 位置

delphi - 是否有更好的方法将所有数据集字段及其属性复制到另一个数据集?

c# - 是否可以告诉 Visual Studio 不要将源文件视为 "component"?

php - Symfony 组件应该如何添加 JavaScript 和 CSS

windows - 特殊字符的cmd字符串替换

无法使用 EnumDisplaySettings 获取所有设备的显示分辨率

delphi - 如何在 GUI 更新期间保持 Delphi 应用程序响应?

delphi - 导入 MSHTML_TLB 会生成 12 Mb 的源文件!

javascript - Angular 组件相对 templateUrl