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

コンポーネント (MyBitBtn) が Windows メッセージを処理している間にコンポーネント (MyBitBtn) を破棄すると、AV が発生します。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 に答える