如何重新排序TCollection中的项目?

时间:2011-11-28 18:20:12

标签: delphi tcollection tcollectionitem

我正在尝试实现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)

3 个答案:

答案 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.SortByDisplayNameMyCollectionItem.Collection.SortByDisplayName