在其事件处理程序中删除FMXobject [英] Deleting an FMXobject inside its event handler

查看:51
本文介绍了在其事件处理程序中删除FMXobject的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下组件, tncrdragdata ( tframedscrollbox ) tdragdata ( tgroupbox )

I have the following components, tncrdragdata (tframedscrollbox) tdragdata (tgroupbox)

主要思想是将它们组合起来并用作列表框(我需要这种方式).

The main Idea is to combine them and use them as a list box (I need it this way).

该分组框包含五个 tedit ,一个tcombobox和一个 tbutton .

The groupbox contains five tedit, one tcombobox and one tbutton.

问题是当我尝试在其事件处理程序中释放 tdragdata 时.

The problem is when I try to free the tdragdata inside its event handler.

我使用 FreeNotification 方法在 framedscrollbox 中重新定位组框.问题是由于某种未知原因,被覆盖的通知方法执行了两次.

I use the FreeNotification method to relocate the group boxes in the framedscrollbox. The problem is that the overridden notification method is executed twice for some reason I don't know.

我的问题是:为什么重写的方法要执行两次?

如果我删除条件(self.components [index]<> AComponent)在重定位项目方法中,我得到了一个AV.调试时,我注意到该方法执行了两次.

If I remove the condition (self.components[index]<>AComponent) in the relocate items method I get an AV. When I debugged this I noticed that the method is executed twice.

这是两个组件的代码:

unit ncrdragdataunit;

interface

uses
  System.SysUtils, System.Classes, FMX.Layouts, FMX.Controls.Presentation,
  FMX.StdCtrls, system.Generics.collections, dragdataunit, FMX.objects, 
  system.types, FMX.graphics, FMX.dialogs, System.Messaging;

type
  Tncrdragdata = class(TFramedScrollBox)
    private
      { private declarations }
      Faddimage: timage;
      Fnextcoor: tpointf;
      Fitemcounter: integer;
      Fncrdata: tlist<tdragdata>;
      Flocate: boolean;
      function calculate_next_coor: tpointf;
      procedure additem(Aname: string);
      procedure relocate_items(AComponent: TComponent);
      procedure createaddimage(path: unicodestring);
      procedure clickaddimage(sender: tobject);
      procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    protected
      { protected declarations }
    public
      { public declarations }
      constructor Create(AOwner: TComponent); override;
      destructor Destroy; override;
      procedure extract_dragdata(var dragdata: tlist<tdragdatafields>);
    published
      { published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('ncrcontrols', [Tncrdragdata]);
end;

{tncrdragdata}

constructor tncrdragdata.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
    {spesific data}
  Fncrdata: = tlist<tdragdata>.create;
  Flocate: = true;
  Fnextcoor.X: = 0;
  Fnextcoor.Y: = -60;
  Fitemcounter: = 0;
  if not(csDesigning in ComponentState) then
  begin
    createaddimage('C:\Users\nacereddine\Desktop\down-arrow-2.png');
    additem('item' + inttostr(Fitemcounter));
  end;
end;

destructor tncrdragdata.Destroy;
begin
  Flocate: = false;
  Faddimage.Free;
  Fncrdata.Free;
  inherited;
end;

function Tncrdragdata.calculate_next_coor: tpointf;
begin
  if(self.componentcount = 0) then
  begin
    result.x: = 20;
    result.y: = 20;
  end
  else
  begin
    result.x: = 20;
    result.y: = Fnextcoor.y + 80;
  end;
end;

procedure Tncrdragdata.additem(Aname: string);
var
  a: tdragdata;
begin
  Fnextcoor: = calculate_next_coor;
  a: = tdragdata.create(self);
  Fncrdata.Add(a);
  inc(Fitemcounter);
  with a do
  begin
    name: = Aname;
    text: = '';
    position.y: = Fnextcoor.y;
    position.x: = Fnextcoor.x;
    parent: = self; // parent name
    a.FreeNotification(self);           <---- this is the problem 
  end;
  Faddimage.Position.X: = Fnextcoor.x + 260;
  Faddimage.Position.y: = Fnextcoor.y + 60;
end;

procedure Tncrdragdata.relocate_items(AComponent: TComponent);
var
  index: Integer;
begin
  if self.componentcount<1 then exit;
  Fnextcoor.X: = 0;
  Fnextcoor.Y: = -60;
  for index: = 1 to self.componentCount-1 do
  begin
    if (self.components[index] is Tdragdata)and(self.components[index]<>AComponent) then
    begin
      Fnextcoor: = calculate_next_coor;
      (self.components[index] as Tdragdata).Position.Y: = Fnextcoor.y;
      (self.components[index] as Tdragdata).Position.x: = Fnextcoor.x;
    end;
  end;
  Faddimage.Position.X: = Fnextcoor.x + 260;
  Faddimage.Position.y: = Fnextcoor.y + 60;
end;

procedure Tncrdragdata.createaddimage(path: unicodestring);
begin
  Faddimage: = timage.Create(self);
  Faddimage.Parent: = self;
  Faddimage.Width: = 40;
  Faddimage.Height: = 40;
  Faddimage.Bitmap.LoadFromFile(path);
  Faddimage.onclick: = clickaddimage;
end;

procedure Tncrdragdata.clickaddimage(sender: tobject);
begin
  additem('item' + inttostr(Fitemcounter));
end;

procedure Tncrdragdata.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (Operation = opRemove) and (AComponent is Tdragdata)and Flocate then
  begin
    relocate_items(AComponent);
    Fncrdata.remove(Tdragdata(AComponent));
  end;
end;

procedure Tncrdragdata.extract_dragdata(var dragdata: tlist<tdragdatafields>);
var
  I: Integer;
begin
  for I: = 0 to Fncrdata.Count-1 do
  begin
    dragdata.Add(Fncrdata.Items[I].dragdatafields);
  end;
end;

end.


unit dragdataunit;

interface

uses
  System.SysUtils, System.Classes, FMX.Types, FMX.Controls,
  FMX.Controls.Presentation, FMX.StdCtrls, FMX.listbox, FMX.edit, System.Messaging;

type
  tsectiontype = (ST_vertical, ST_curved, ST_straight);

  tdragdatafields = record
  TVD, MD, VS, Inc, Alfa30: single;
  sectiontype: tsectiontype;
  end;

  tdragdatafield = (df_TVD, df_MD, df_VS, df_Inc, df_Alfa30);

  tdragdata = class(tgroupbox)
    private
      (* private declarations *)
      Fdata: array[0..4] of single;
      OTVD, OMD, OVS, OInc, OAlfa30: tedit;
      Fsectiontype: tsectiontype;
      Osectiontype: tcombobox;
      headerlabel: tlabel;
      Odeletebtn: tbutton;
      procedure onchangevalue(sender: tobject);
      procedure ondeletebtnclick(sender: tobject);
      function getdata: tdragdatafields;
    protected
      (* protected declarations *)
    public
      (* public declarations *)
      constructor Create(AOwner: TComponent); override;
      destructor Destroy; override;

    published
      (* published declarations *)
      property dragdatafields: tdragdatafields read getdata;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('ncrcontrols', [Tdragdata]);
end;

{tdragdata}
constructor tdragdata.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
    {spesific data}
  SetBounds(10, 10, 550, 60);
  self.Text: = '';
  OTVD: = tedit.create(self);
  with OTVD do
  begin
    text: = '';
    SetBounds(10, 30, 80, 21);
    onchange: = onchangevalue;
    parent: = self;
  end;
  OMD: = tedit.create(self);
  with OMD do
  begin
    text: = '';
    SetBounds(100, 30, 80, 21);
    onchange: = onchangevalue;
    parent: = self;
  end;
  OVS: = tedit.create(self);
  with OVS do
  begin
    text: = '';
    SetBounds(190, 30, 80, 21);
    onchange: = onchangevalue;
    parent: = self;
  end;
  OInc: = tedit.create(self);
  with OInc do
  begin
    text: = '';
    SetBounds(280, 30, 80, 21);
    onchange: = onchangevalue;
    parent: = self;
  end;
  OAlfa30: = tedit.create(self);
  with OAlfa30 do
  begin
    text: = '';
    SetBounds(370, 30, 80, 21);
    onchange: = onchangevalue;
    parent: = self;
  end;
  Osectiontype: = tcombobox.create(self);
  with Osectiontype do
  begin
    SetBounds(460, 30, 80, 21);
    items.Add('STvertical');
    items.Add('STcurved');
    items.Add('STstraight');
    //Selected.Text: = 'STvertical';
    onchange: = onchangevalue;
    parent: = self;
  end;

  headerlabel: = tlabel.create(self);
  with headerlabel do
  begin
    text: = 'TVD (m)              MD (m)                VS (m)                '
         + 'Inc (°)                  Alfa (°/30m)         Section type';
    SetBounds(10, 9, 560, 21);
    parent: = self;
  end;
  Odeletebtn: = tbutton.create(self);
  with Odeletebtn do
  begin
    text: = '';
    SetBounds(537, 9, 10, 10);
    parent: = self;
    onclick: = ondeletebtnclick;
  end;

end;

destructor tdragdata.Destroy;
begin
  OTVD.free;
  OMD.free;
  OVS.free;
  OInc.free;
  OAlfa30.free;
  Osectiontype.free;
  headerlabel.free;
  Odeletebtn.Free;
  inherited;
end;

procedure tdragdata.onchangevalue(sender: tobject);

  function getvalue(st: tedit): single;
  begin
    try
      result: = strtofloat(st.Text);
    except
      result: = -1;
      st.Text: = '-1';
    end;
  end;

  function gettype(st: tcombobox): tsectiontype;
  begin
    if st.Selected.Text = 'STvertical' then result: = ST_vertical
    else if st.Selected.Text = 'STcurved' then result: = ST_vertical
    else if st.Selected.Text = 'STstraight' then result: = ST_vertical
    else begin result: = ST_vertical;  end;
  end;

begin
  if sender = OTVD then
  begin
    Fdata[ord(df_TVD)]: = getvalue(OTVD);
  end
  else
  begin
    if sender = OMD then
    begin
      Fdata[ord(df_MD)]: = getvalue(OMD);
    end
    else
    begin
      if sender = OVS then
      begin
        Fdata[ord(df_VS)]: = getvalue(OVS);
      end
      else
      begin
        if sender = OInc then
        begin
          Fdata[ord(df_Inc)]: = getvalue(OInc);
        end
        else
        begin
          if sender = OAlfa30 then
          begin
              Fdata[ord(df_Alfa30)]: = getvalue(OAlfa30);
          end
          else
          begin
            if sender = Osectiontype then
            begin
              Fsectiontype: = gettype(Osectiontype);
            end
            else
              Exception.Create('sender unknown');
            end;
          end;
        end;
      end;
    end;
  end;

function tdragdata.getdata: tdragdatafields;
begin
  result.TVD: = Fdata[ord(df_TVD)];
  result.MD: = Fdata[ord(df_MD)];
  result.VS: = Fdata[ord(df_VS)];
  result.Inc: = Fdata[ord(df_Inc)];
  result.Alfa30: = Fdata[ord(df_Alfa30)];
  result.sectiontype: = Fsectiontype;
end;

procedure tdragdata.ondeletebtnclick(sender: tobject);
begin
  self.Release;
end;

end.

推荐答案

我发现了有关 FreeNotification()方法

使用FreeNotification将AComponent注册为应在组件将要销毁时收到通知.这只是当组件位于不同的位置时,需要用这种方式注册组件表单或拥有其他所有者.例如,如果AComponent位于另一种形式并使用该组件来实现属性,它必须调用FreeNotification,以便在以下情况下调用其Notification方法组件被销毁.

Use FreeNotification to register AComponent as a component that should be notified when the component is about to be destroyed. It is only necessary to register components this way when they are in a different form or have a different owner. For example, if AComponent is in another form and uses the component to implement a property, it must call FreeNotification so that its Notification method is called when the component is destroyed.

对于具有相同所有者的组件,将调用Notification方法当应用程序明确释放组件时自动.隐式释放组件时,不会发出通知,因为所有者已经被释放.

For components with the same owner, the Notification method is called automatically when an application explicitly frees the component. This notification is not sent out when components are freed implicitly, because the Owner is already being freed.

然后我删除该行

a.FreeNotification(self);

在方法中(第一个组件)

In the method (the first component)

procedure Tncrdragdata.additem(Aname:string);

问题消失了.

我认为问题在于我正在使用Tdragdata调用FreeNotification()方法,而没有其他所有者.显然我在违反规则.

I think the problem is that I was calling the FreeNotification() method with Tdragdata, not having a different owner. Clearly I was breaking a rule.

感谢@victoria和@CraigYoung的帮助.

Thanks to @victoria and @CraigYoung for their help.

这篇关于在其事件处理程序中删除FMXobject的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆