2011-11-28 2 views
4

TCollection 내에서 선택한 행을 위 또는 아래로 이동하는 MoveItemUp 및 MoveItemDown 메서드를 구현하려고합니다.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; 

를 그에게 방법을 제공 델파이 IDE 자체 디자인 타임에서 수행으로 나는이 런타임에 가능해야 상당히 확신 :

다음 코드는 작동하지 않습니다 된 TCollection의 내 서브 클래스에 추가 컬렉션 항목을 목록에서 재정렬하십시오. 나는 어떤 객체를 생성, 파괴 또는 할당하지 않고 기존 객체의 순서를 변경하여이 작업을 수행하기를 바라고 있습니다. 이것은 Classes.pas TCollection의 서브 클래스에서 가능합니까? (그렇지 않다면 소스 클론에서 내 자신의 TCollection을 만들어야 할 수도 있습니다)

+10

컬렉션 아이템의'Index' 속성을 설정하면'Item.Index : = Item.Index + 1' (이것은 콜렉션의 아이템리스트의'Move')를 호출해야합니다. 특별한 처리가 필요하다면'SetIndex' 메쏘드가 오버라이드 될 것입니다. –

답변

8

VCL 소스에 따르면 수동으로 수행 할 필요가 없습니다. 단순히 @Sertac과 같은 Index 속성을 설정하면 정상적으로 작동합니다. 소스가있는 경우 TCollectionItem.SetIndex 코드를 확인하십시오.

+2

감사 Sertac. 이 답변은 본질적으로 귀하의 아이디어를 복사하지만 대답으로 게시되었습니다. \ –

+0

여러분을 환영합니다! –

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; 
+0

오, 그렇게 많이하지 않습니다. 내 자신의 희망 클래스를 올바르게 사용하여 개인 회원을 크래킹하는 것에 서브 클래 싱 하시겠습니까? –

+0

예. 그것이 내가 해킹 같은 것으로 언급 한 이유입니다. 콜렉션의 아이템을 정렬하려고 할 때'Index'를 사용하는 데 어려움을 겪었고, 교환은 구현되지 않았습니다. –

+0

항목을 위/아래로 한 위치 (내가하려는 중)로 이동하면 TcollectionItem.Index가 할당되어 제대로 작동하는 것 같습니다. –

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.

+0

엠바 카데로가 마침내 클래스 헬퍼 하나만 범위에있을 수있는 문제를 해결 했습니까? 그렇지 않은 경우, 이것은 TCollection의 범위에 기존 도우미가없는 경우에만 작동하며 나중에 다른 도우미가 범위에 도입되면 중단됩니다. – Deltics

+0

@Deltics, 클래스 도우미의 범위는 변경되지 않았습니다. 헬퍼를 서브 클래스화할 가능성이 있지만, 전체 체인을 제어 할 수 있어야합니다.다른 가능성으로는 Ken 쇼와 같은 해킹과 컬렉션에서이를 수행하는 글로벌 프로 시저를 작성하거나 클래스/레코드 내부에서 컬렉션을위한 더 많은 "도우미"루틴을 수집 할 수 있습니다. –

+0

** 왜 ** :'i : = 0 ~ for Self.Count -1은 SL.AddObject (Items [i] .DisplayName), Items [i])일까요? SL.Sort; i = 0 ~ SL.Count -1은 TCollectionItem (SL.Objects [i])입니다. 인덱스 : = i;' – Vassilis

관련 문제