在其事件处理程序

时间:2017-06-11 18:31:58

标签: delphi firemonkey delphi-10-seattle

我有以下组件,tncrdragdatatframedscrollboxtdragdatatgroupbox

主要想法是将它们组合起来并将它们用作列表框(我需要这样做)。

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

问题在于我尝试在其事件处理程序中释放tdragdata

我使用FreeNotification方法重新定位framedscrollbox中的组框。问题是被覆盖的通知方法由于某种我不知道的原因而被执行两次。

我的问题是:为什么被覆盖的方法被执行两次?

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

这是两个组件的代码:

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.

1 个答案:

答案 0 :(得分:1)

我发现了FreeNotification()方法here的一些有趣内容。

  

使用FreeNotification将AComponent注册为应该的组件   在组件即将被销毁时得到通知。 这是唯一的   当它们处于不同的状态时,必须以这种方式注册组件   形成或拥有不同的所有者。例如,如果AComponent在   另一种形式并使用该组件来实现一个属性,它必须   调用FreeNotification以便在调用Notification方法时调用它   组件被销毁。

     

对于具有相同所有者的组件,将调用Notification方法   当应用程序显式释放组件时自动。这   隐式释放组件时不发送通知,   因为所有者已被释放。

然后我删除了这行

a.FreeNotification(self);

在方法(第一部分)中

procedure Tncrdragdata.additem(Aname:string);

问题已经消失。

我认为问题在于我使用Tdragdata调用FreeNotification()方法,而不是拥有不同的所有者。显然,我违反了规则。

感谢@victoria和@CraigYoung的帮助。