我正在尝试实现MoveItemUp和MoveItemDown方法,这些方法可以在TCollection
内的一个索引上向上或向下移动选定的行。
以下代码添加到我的TCollection子类中不起作用:
procedure TMyCollection.MoveRowDown(index: Integer);
var
item:TCollectionItem;
begin
if index>=Count-1 then exit;
item := Self.Items[index];
Self.Delete(index); // whoops this destroys the item above.
Self.Insert(index+1);
Self.SetItem(index+1,item); // this actually does an assign from a destroyed object.
end;
我很确定这必须在运行时可行,因为它在设计时由Delphi IDE本身完成,它提供了一种重新排序列表中的Collection项的方法。我希望通过简单地重新排序现有对象来实现这一点,而无需创建,销毁或分配任何对象。这可能来自Classes.pas TCollection的子类吗? (如果没有,我可能必须从源克隆中创建自己的TCollection)
答案 0 :(得分:9)
根据VCL来源,您无需手动执行此操作。只需像@Sertac建议的那样设置Index
属性,它应该可以正常工作。如果您有来源,请查看TCollectionItem.SetIndex
的代码。
答案 1 :(得分:4)
您可以使用类似的内容 - 为集合声明一个虚拟类类型,并使用它来访问该集合的内部FItems
,即TList
。然后,您可以使用TList.Exchange
方法来处理实际移动(或TList
的任何其他功能)。
type
{$HINTS OFF}
TCollectionHack = class(TPersistent)
private
FItemClass: TCollectionItemClass;
FItems: TList;
end;
{$HINTS ON}
// In a method of your collection itself (eg., MoveItem or SwapItems or whatever)
var
TempList: TList;
begin
TempList := TCollectionHack(Self).FItems;
TempList.Exchange(Index1, Index2);
end;
答案 2 :(得分:0)
这是一个按DisplayName排序的类助手解决方案:如果您愿意,可以改进排序,我使用TStringList为我做排序。在您引用包含类助手的单元的任何地方都可以使用类助手,因此如果您有一个实用程序单元,则将其放在那里。
interface
TCollectionHelper = class helper for TCollection
public
procedure SortByDisplayName;
end;
Implementation
procedure TCollectionHelper.SortByDisplayName;
var i, Limit : integer;
SL: TStringList;
begin
SL:= TStringList.Create;
try
for i := self.Count-1 downto 0 do
SL.AddObject(Items[i].DisplayName, Pointer(Items[i].ID));
SL.Sort;
Limit := SL.Count-1;
for i := 0 to Limit do
self.FindItemID(Integer(SL.Objects[i])).Index := i;
finally
SL.Free;
end;
end;
然后使用该方法只是假装它是TCollection类的一种方法。这也适用于TCollection的任何子类。
MyCollection.SortByDisplayName
或MyCollectionItem.Collection.SortByDisplayName
。