2017-06-11 70 views
0

我有以下組成部分,tncrdragdatatframedscrollboxtdragdatatgroupbox刪除FMXobject的事件處理程序內

主要思路是將它們結合起來,並把它們作爲一個列表框(我需要它這樣)。

該組框包含五個tedit,一個tcombobox和一個tbutton

問題是當我嘗試釋放其事件處理程序中的tdragdata。我使用FreeNotification方法來重定位framedscrollbox中的組框。問題是重寫的通知方法由於某些原因而執行了兩次,我不知道。

我的問題是:爲什麼重寫的方法執行兩次?

如果我刪除條件(self.components[index]<>AComponent) 在relocate items方法我得到一個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. 
+0

你爲自己調試的方式:1)編譯調試DCU的啓用。 2)在你感興趣的方法上放置一個斷點(即你的重寫FreeNotification的開始)3)當你的程序碰到斷點時,打開Callstack窗口。學習這個會告訴你爲了達到該方法而採取的執行路徑。 4)繼續運行並重復步驟3. –

+0

@CraigYoung謝謝你的幫助。 –

回答

1

我發現了一些有趣的FreeNotification()方法here

使用FreeNotification將AComponent註冊爲在組件即將銷燬時應通知 的組件。 只有在 表單中有這種註冊組件的必要條件時才需要註冊組件,或者擁有不同的所有者。例如,如果AComponent處於 另一種形式並使用該組件實現屬性,則必須調用FreeNotification,以便在銷燬該組件時調用其通知方法 。

對於具有相同所有者的組件,通知方法在應用程序明確釋放組件時自動調用 。這個 隱式地釋放組件時不會發送通知,因爲所有者已被釋放,所以不會發送通知 。

,然後當我除去線

a.FreeNotification(self); 

在方法(第一組分)

procedure Tncrdragdata.additem(Aname:string); 

而問題就消失了。

我認爲問題是我用Tdragdata調用了FreeNotification()方法,沒有其他所有者。很明顯,我打破了一個規則。

感謝@victoria和@CraigYoung的幫助。