ListView에서 Theme를 켜고 GroupView를 True로 세팅하면 위와같이 Group으로 볼수 있다.

Group의 순서를 바꾸려면 아래와 같이 작업한다.

2010버전에서는 Group 정렬이 따로 빠져나와있지 않아서 CommCtrl을 참조했다.


1. 정렬시 전달할 사용자 데이터 구조체를 선언

type

  PGroupSortData = ^TGroupSortData;

  TGroupSortData = record

    ListView: TListview;

    ColumnIndex: Integer;

    Ascend: Boolean;

  end;



2. 정렬시 호출할 콜백 함수 구현

function ListView_GroupSort(Group1_ID: Integer; Group2_ID: Integer; pvData: Pointer): Integer; stdcall;

var

  GroupSortData: PGroupSortData;

  Str1, Str2: string;

begin

  GroupSortData := PGroupSortData(pvData);


  Str1 := GroupSortData.ListView.Groups.Items[Group1_ID].Header;

  Str2 := GroupSortData.ListView.Groups.Items[Group2_ID].Header;


  Result := CompareText( Str1, Str2 );

  if not GroupSortData.Ascend then

    Result := -Result;

end;


그룹 헤더값을 비교해서 결과값을 리턴한다.



3. uses에 CommCtrl 선언



4. 정렬 실행

var

  GroupSortData: TGroupSortData;

begin

  GroupSortData.ListView := ListView1;

  GroupSortData.Ascend := FAscend;

  GroupSortData.ColumnIndex := Column.Index;


  ListView_SortGroups( ListView1.Handle, ListView_GroupSort, @GroupSortData );


  FAscend := not FAscend;
end; 


LVM_SORTGROUPS 메시지를 쏘는 것으로 CommCtrl.pas를 참조한다.

VC의 CommCtrl.h에 있는 매크로와 동일하다.


5. exe demo & source


===============================================
20110919 수정사항 추가

    else if Str1[Pos1] = #0 then
    begin
      Result := 0;
      Exit;
    end

에셔 결과값 0을 -1로 변경해야함.

================================================


---------
a - 1
a - 10
a - 99
a - 9
a - 10000
---------
위와 같은 데이터가 있을때

델파이의 CompareStr로 비교하면
---------
a - 1
a - 10
a - 10000
a - 9
a - 99
---------
로 나옵니다.

윈도우탐색기에서 입력해보면
--------
a - 1
a - 9
a - 10
a - 99
a - 10000
--------
으로 정렬됩니다.


출처는 http://www.scottandmichelle.net/scott/code/index2.mv?codenum=100 입니다.
씨 소스로 되어있길래 포팅해봤습니다.

function NaturalOrderCompareString( const A1, A2: string; ACaseSensitive: Boolean ): Integer;
var
  Str1, Str2: PChar;
  Pos1, Pos2: Integer;
  EndPos1, EndPos2: Integer;
begin
  Str1 := PChar(A1);
  Str2 := PChar(A2);

  Pos1 := -1;
  Pos2 := -1;

  while True do
  begin
    Inc( Pos1 );
    Inc( Pos2 );

    if (Str1[Pos1] = #0) and (Str2[Pos2] = #0) then
    begin
      Result := 0;
      Exit;
    end
    else if Str1[Pos1] = #0 then
    begin
      Result := -1;
      Exit;
    end
    else if Str2[Pos2] = #0 then
    begin
      Result := 1;
      Exit;
    end;

    if (Str1[Pos1] >= '0') and (Str1[Pos1] <= '9') and
       (Str2[Pos2] >= '0') and (Str2[Pos2] <= '9') then
    begin
      EndPos1 := Pos1;
      repeat
        Inc(EndPos1);
      until not ((Str1[EndPos1] >= '0') and (Str1[EndPos1] <= '9'));

      EndPos2 := Pos2;
      repeat
        Inc(EndPos2);
      until not ((Str2[EndPos2] >= '0') and (Str2[EndPos2] <= '9'));

      while True do
      begin
        if EndPos1 - Pos1 = EndPos2 - Pos2 then
        begin
          // 이부분이 숫자비교임. StrToInt 한 다음에 빼도 될 것임
          Result := CompareStr( Copy(Str1, Pos1+1, EndPos1 - Pos1),  Copy(Str2, Pos2+1, EndPos1 - Pos1) ) ;

          if Result = 0 then
          begin
            Pos1 := EndPos1 - 1;
            Pos2 := EndPos2 - 1;
            Break;
          end
          else
          begin
            Exit;
          end;
        end
        else if EndPos1 - Pos1 > EndPos2 - Pos2 then
        begin
          if Str1[Pos1] = '0' then
            Inc(Pos1)
          else
          begin
            Result := 1;
            Exit;
          end;
        end
        else
        begin
          if Str2[Pos2] = '0' then
            Inc( Pos2 )
          else
          begin
            Result := -1;
            Exit;
          end;
        end;
      end;
    end
    else
    begin
      if ACaseSensitive then
        Result := CompareStr( Copy(Str1, Pos1, 1), Copy(Str2, Pos2, 1) )
      else
        Result := CompareText( Copy(Str1, Pos1, 1), Copy(Str2, Pos2, 1) );

      if Result <> 0 then
        Exit;
    end;
  end;
end;



리스트뷰 OnCompare에 델파이의 CompareStr, NaturalOrderCompareString 함수, Windows 유닛 내의 CompareString 함수로 정렬해서 비교한 간단한 예제가 있으니 비교해보시기 바랍니다.

정렬부분 소스는
procedure TForm3.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
  Data: Integer; var Compare: Integer);
var
  CompareResult: Integer;
begin
  case ComboBox1.ItemIndex of
    0:
    begin
      // Na
      Compare := NaturalOrderCompareString( Item1.Caption, Item2.Caption, True );
    end;
    1:
    begin
      // 일반 문자열 비교
      Compare := CompareStr( Item1.Caption, Item2.Caption );
    end;
    2:
    begin
      // Window API
      CompareResult := CompareString( LOCALE_USER_DEFAULT, 0, PChar(Item1.Caption), Length(Item1.Caption), PChar(Item2.Caption), Length(Item2.Caption) );

      case CompareResult of
        CSTR_LESS_THAN:     Compare := -1;
        CSTR_GREATER_THAN:  Compare := 1;
        CSTR_EQUAL:         Compare := 0;
      end;
    end;
  end;
end;


+ Recent posts