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).
The groupbox contains five tedit, one tcombobox and one tbutton.
The problem is when I try to free the tdragdata inside its event handler.
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.
My question is: Why the overridden method is executed twice?
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.
This is the code for the two components:
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) 3) When your program hits the breakpoint, open the Callstack Window. Studying this this will tell you the execution path taken to get to the method. 4) Continue running and repeat step 3. - Disillusioned