【问题标题】:how can i free a Tpanel That have a TbitBtn that calls to free the Tpanel我怎样才能释放一个 Tpanel,它有一个调用释放 Tpanel 的 TbitBtn
【发布时间】:2012-08-06 07:45:17
【问题描述】:

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

【问题讨论】:

    标签: windows delphi components delphi-7


    【解决方案1】:

    发生 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

    【讨论】:

    • 关于这个的还有一个问题......不要开始另一个话题。你能告诉我如何使用我的 FindComponentEx 来查找特定的面板,以便我可以通过 wParam 或 lParam 删除它...谢谢
    【解决方案2】:
    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; 
    

    【讨论】:

    • 如果FindComponentEx函数是为了找到合适的组件,你可以检查一下你的TsPanel.Destroy里面。做个断点调试会更容易找到问题。
    猜你喜欢
    • 2013-01-28
    • 1970-01-01
    • 1970-01-01
    • 2018-07-21
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    • 2011-05-01
    • 2017-09-27
    相关资源
    最近更新 更多