我有自己的组件(TNiftyRVFrameWithPopups)和TOwnedCollection作为属性(TagList)。
每次我向TagList添加项时,都应该将同一项添加到另一个对象(FMenu)中。这是由RefreshMenu在设计时从TNiftyRVFrameWithPopups.Loaded调用的过程执行的。
我的问题是我不能在运行时添加项,因为没有调用TNiftyRVFrameWithPopups.Loaded。
我原以为有一种解决方案是Postmessage,但我没能成功。
资料来源如下:
TNiftyListTag = class(TCollectionItem)
private
FTagValue: string;
FDisplayTextTag: string;
public
procedure Assign(Source: TPersistent); override;
published
property DisplayTag: string read FDisplayTextTag write FDisplayTextTag;
property Value: string read FTagValue write FTagValue;
end;
TNiftyListTags = class(TOwnedCollection)
protected
function GetItem(Index: Integer): TNiftyListTag;
procedure SetItem(Index: Integer; Value: TNiftyListTag);
public
constructor Create(AOwner: TPersistent; ItemClass: TCollectionItemClass);
function Add: TNiftyListTag;
end;
TNiftyRVFrameWithPopups = class(TRVEditFrame)
private
FMenu: TAdvSmoothListBox;
FMenuList: TStringList;
FCollectionTags: TNiftyListTags;
procedure SetCollectionTags(const Value: TNiftyListTags);
procedure RefreshMenu;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
procedure Loaded; override;
published
property TagList: TNiftyListTags read FCollectionTags write SetCollectionTags;
end;
implementation
constructor TNiftyRVFrameWithPopups.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMenuList := TStringList.Create;
FCollectionTags := TNiftyListTags.Create(Self, TNiftyListTag);
end;
procedure TNiftyRVFrameWithPopups.SetCollectionTags(const Value: TNiftyListTags);
begin
FCollectionTags.Assign(Value);
end;
procedure TNiftyRVFrameWithPopups.RefreshMenu;
var
i: Integer;
begin
FMenu.Items.Clear;
for i := 0 to FCollectionTags.Count - 1 do
begin
FMenu.Items.Add;
FMenu.Items.Items[i].Caption := FCollectionTags.Items[i].FDisplayTextTag;
end;
end;
procedure TNiftyRVFrameWithPopups.Loaded;
begin
inherited Loaded;
if Assigned(FRVEditor) then
begin
RefreshMenu;
end;
end;
{ TNiftyListTag }
procedure TNiftyListTag.Assign(Source: TPersistent);
begin
if Source is TNiftyListTag then
begin
FTagValue := TNiftyListTag(Source).FTagValue;
FDisplayTextTag := TNiftyListTag(Source).FDisplayTextTag;
end
else
inherited;
end;
{ TNiftyListTags }
function TNiftyListTags.Add: TNiftyListTag;
begin
Result := TNiftyListTag(inherited Add);
end;
constructor TNiftyListTags.Create(AOwner: TPersistent; ItemClass: TCollectionItemClass);
begin
inherited Create(AOwner, ItemClass);
end;
procedure TNiftyListTags.SetItem(Index: Integer; Value: TNiftyListTag);
begin
inherited SetItem(index, Value);
end;
function TNiftyListTags.GetItem(Index: Integer): TNiftyListTag;
begin
Result := TNiftyListTag(inherited GetItem(Index));
end;编辑
在德尔特斯的建议下,我修改了我的代码:
TNiftyListTag = class(TCollectionItem)
private
FTagValue: string;
FDisplayTextTag: string;
public
procedure Assign(Source: TPersistent); override;
published
property DisplayTag: string read FDisplayTextTag write FDisplayTextTag;
property Value: string read FTagValue write FTagValue;
end;
TNiftyListTags = class(TOwnedCollection)
private
fOnChanged: TNotifyEvent;
procedure DoOnChanged;
protected
function GetItem(Index: Integer): TNiftyListTag;
procedure SetItem(Index: Integer; Value: TNiftyListTag);
public
constructor Create(AOwner: TPersistent; ItemClass: TCollectionItemClass);
function Add: TNiftyListTag;
procedure AppendItem(const aDisplayText, aTag: string);
end;
TNiftyRVFrameWithPopups = class(TRVEditFrame)
private
FMenu: TAdvSmoothListBox;
FMenuList: TStringList;
FCollectionTags: TNiftyListTags;
procedure RefreshMenu;
procedure SetCollectionTags(const Value: TNiftyListTags);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Loaded; override;
published
property TagList: TNiftyListTags read FCollectionTags write SetCollectionTags;
end;
implementation
constructor TNiftyRVFrameWithPopups.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMenuList := TStringList.Create;
FCollectionTags := TNiftyListTags.Create(Self, TNiftyListTag);
FCollectionTags.fOnChanged := RefreshMenu;
end;
destructor TNiftyRVFrameWithPopups.Destroy;
begin
FreeAndNil(FMenuList);
FCollectionTags.Free;
inherited;
end;
procedure TNiftyRVFrameWithPopups.RefreshMenu;
var
i: Integer;
begin
FMenu.Items.Clear;
for i := 0 to FCollectionTags.Count - 1 do
begin
FMenu.Items.Add;
FMenu.Items.Items[i].Caption := FCollectionTags.Items[i].FDisplayTextTag;
end;
end;
procedure TNiftyRVFrameWithPopups.Loaded;
begin
inherited Loaded;
RefreshMenu(Self);
end;
procedure TNiftyRVFrameWithPopups.RefreshMenu;
var
i: Integer;
begin
if Assigned(FRVEditor) then
begin
(FRVEditor as TCustomRichViewEdit).OnRVMouseUp := OnMouseUp;
FMenu.Parent := FRVEditor;
fmenu.Items.Clear;
for i := 0 to FCollectionTags.Count - 1 do
begin
FMenu.Items.Add;
FMenu.Items.Items[i].Caption := FCollectionTags.Items[i].FDisplayTextTag;
end;
end;
end;
procedure TNiftyRVFrameWithPopups.SetCollectionTags(const Value: TNiftyListTags);
begin
FCollectionTags.Assign(Value);
end;
{ TNiftyListTag }
procedure TNiftyListTag.Assign(Source: TPersistent);
begin
if Source is TNiftyListTag then
begin
FTagValue := TNiftyListTag(Source).FTagValue;
FDisplayTextTag := TNiftyListTag(Source).FDisplayTextTag;
end
else
inherited;
end;
{ TNiftyListTags }
function TNiftyListTags.Add: TNiftyListTag;
begin
Result := TNiftyListTag(inherited Add);
end;
procedure TNiftyListTags.AppendItem(const aDisplayText, aTag: string);
var
a: TNiftyListTag;
begin
a := TNiftyListTag(inherited Add);
a.FTagValue := aTag;
a.FDisplayTextTag := aDisplayText;
DoOnChanged;
end;
constructor TNiftyListTags.Create(AOwner: TPersistent; ItemClass: TCollectionItemClass);
begin
inherited Create(AOwner, ItemClass);
end;
procedure TNiftyListTags.DoOnChanged;
begin
if Assigned(fOnChanged) then
fOnChanged(self);
end;
procedure TNiftyListTags.SetItem(Index: Integer; Value: TNiftyListTag);
begin
inherited SetItem(index, Value);
end;
function TNiftyListTags.GetItem(Index: Integer): TNiftyListTag;
begin
Result := TNiftyListTag(inherited GetItem(Index));
end;
procedure TNiftyListTags.SetItem(Index: Integer; Value: TNiftyListTag);
begin
inherited SetItem(index, Value);
DoOnChanged;
end;
end.可以通过以下方式在运行时添加项:
var
a:TNiftyRVFrameWithPopups;
begin
a:=TNiftyRVFrameWithPopups.Create(self);
.....
a.TagList.AppendItem('a','b');
a.TagList.AppendItem('c','d');
end发布于 2015-08-08 22:18:32
您的TNiftyListTags由TNiftyRVFrameWithPopups.拥有
您唯一的‘问题’是,TOwnedCollection类没有向所有者提供类型化引用,通过它调用必要的方法来在集合更改时刷新所有者。
有很多方法可以实现你想要的。但是,在介绍选项之前,我建议您不要调用加载的来实现更新/刷新,因为这种方法有特定的意义。虽然重写方法中的代码在此上下文中可能是安全的,但继承的实现可能并不安全。
我建议将if Assigned(fRVEditor)预条件检查移到RefreshMenu本身。然后,加载了RefreshMenu,的简单地调用RefreshMenu,就像其他可能需要调用的代码一样,这些代码具有由方法本身检查的必要的预条件。
现在,关于如何和何时调用RefreshMenu方法,一个简单的机制是在集合的内容发生变化时直接调用refresh方法。例如,在中添加集合的方法。由于您使用的是TOwnedCollection作为基类,所以只需键入所有者。
function TNiftyListTags.Add: TNiftyListTag;
begin
Result := TNiftyListTag(inherited Add);
TNiftyRVFrameWithPopups(Owner).RefreshMenu;
end;但是,这会将您的集合类直接连接到充当所有者的特定组件。如果您的集合专门针对这个类,那么这可能是有效的,但它仍然是不可取的。
要将集合从组件中分离出来,您可以在集合上引入一个OnChange事件。一个简单的TNotifyEvent通常就足够了。
然后,无论哪个组件拥有该集合,都可以为此事件安装一个处理程序。每当集合发生更改时,调用OnChange处理程序。在这种情况下,TNiftyRVFrameWithPopups组件将通过调用自己的RefreshMenu方法来响应这些更改。
procedure TNiftyListTags.DoOnChanged;
begin
if Assigned(fOnChanged) then
fOnChanged(self);
end;
function TNiftyListTags.Add: TNiftyListTag;
begin
Result := TNiftyListTag(inherited Add);
DoOnChanged;
end;
procedure TNiftyRVFrameWithPopups.OnTagsChanged(Sender: TObject);
begin
RefreshMenu;
end;这通常是我采用的方法,我将OnChange事件作为私有实现细节,由组件实例化集合在构造函数中指定处理程序。这可以防止任何人无意中通过任何公共属性替换事件处理程序。
constructor TNiftyRVFrameWithPopups.Create(Owner: TComponent);
begin
inherited Create(self);
fTags := TNiftyListTags.Create(self, OnTagsChanged);
..
end;为了方便这一点,您显然需要一个自定义构造函数来接受事件处理程序:
TNiftyListTags = class(TOwnedCollection)
..
private
fOnChanged: TNotifyEvent;
public
constructor Create(aOwner: TPersistent; aOnChange: TNotifyEvent); reintroduce;
..
end;
constructor TNiftyListTags.Create(aOwner: TPersistent;
aOnChange: TNotifyEvent);
begin
inherited Create(aOwner, TNiftyListTag);
fOnChange := aOnChange;
end;注意,继承的构造函数还接受两个参数,第二个参数是集合项的类。如果您正在引入自定义构造函数,您可以从您自己的构造函数的参数中删除它,只需在继承的创建调用中指定item类。
注意:这不会增加集合和item类之间的耦合--根据定义(和设计),它们已经紧密耦合。
https://stackoverflow.com/questions/31896757
复制相似问题