How to reorder items in TCollection?

I am trying to implement the MoveItemUp and MoveItemDown methods that move the selected row up or down one index in a TCollection .

The following code added to my TCollection subclass does not work:

 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; 

I am sure that this should be possible at runtime, as it was during the development of the Delphi IDE itself, which provides a way to change the order of the elements in a collection in a list. I hope to do this by simply reordering existing objects without creating, destroying, or assigning any objects. Is this possible from a subclass of Classes.pas TCollection? (If not, I may have to make my own TCollection from the original clone)

+4
source share
3 answers

According to the VCL source, you do not need to do this manually. Just set the Index property as suggested by @Sertac, and it should work fine. If you have a source, check the TCollectionItem.SetIndex code.

+8
source

You can use something like this: declare a type of type dummy for the collection and use it to access the internal FItems this collection, which is a TList . You can then use the TList.Exchange method to handle the actual move (or any other TList functions, of course).

 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; 
+4
source

Here is a helper class solution that sorts by DisplayName: you can improve sorting if you want, I used a TStringList to sort for me. The class helper is available wherever you refer to a device containing a helper class, so if you have a utility, put it there.

 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; 

Then, to use the method, simply pretend that it is a method of the TCollection class. This works in any subclass of TCollection.

MyCollection.SortByDisplayName or MyCollectionItem.Collection.SortByDisplayName .

0
source

Source: https://habr.com/ru/post/1383479/


All Articles