我有以下组件,tncrdragdata
(tframedscrollbox
)tdragdata
(tgroupbox
)
主要想法是将它们组合起来并将它们用作列表框(我需要这样做)。
组框包含五个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.
答案 0 :(得分:1)
我发现了FreeNotification()
方法here的一些有趣内容。
使用FreeNotification将AComponent注册为应该的组件 在组件即将被销毁时得到通知。 这是唯一的 当它们处于不同的状态时,必须以这种方式注册组件 形成或拥有不同的所有者。例如,如果AComponent在 另一种形式并使用该组件来实现一个属性,它必须 调用FreeNotification以便在调用Notification方法时调用它 组件被销毁。
对于具有相同所有者的组件,将调用Notification方法 当应用程序显式释放组件时自动。这 隐式释放组件时不发送通知, 因为所有者已被释放。
然后我删除了这行
a.FreeNotification(self);
在方法(第一部分)中
procedure Tncrdragdata.additem(Aname:string);
问题已经消失。
我认为问题在于我使用Tdragdata调用FreeNotification()方法,而不是拥有不同的所有者。显然,我违反了规则。
感谢@victoria和@CraigYoung的帮助。