C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 FAQ
C++Builder Programming FAQ
[12] [TECHNIQUE][COMPONENT] 리스트뷰에서 컬럼클릭했을때 정렬
박지훈.임프 [cbuilder] 19124 읽음    2000-06-13 00:00
/A//
리스트뷰에 대해서 질문을 드립니다.
마이크로소프트의 OutLook에 주소록이 있습니다.
이 주소록을 실행시켜 보면, 리스트뷰에 사람이름과 그에 해당하는 내용들이 나옵니다.
리스트 뷰의 컬럼중에 이름이라고 써있는 부분을 클릭하면 이름순서대로 정렬됩니다.
또 전화번호라고 써있는 컬럼을 클릭하면 전화번호 순서대로 정렬됩니다.
이렇게 컬럼을 클릭하여  그에 해당하는 내용대로 정렬되는 것은 다른 프로그램에서도 볼수가 있습니다.
예를 들면, WinRar이나 WinZip같은 프로그램에서 말이죠.

어떻게 제 프로그램에서 이런방법으로 리스트뷰의 내용을 정렬 시키는 방법을 알고 싶습니다.



/A//

리스트뷰의 컬럼을 클릭했을때 OnColumnClick이라는 이벤트가 발생합니다.
그러므로 이 이벤트에 핸들러를 달아주고 처리해주면 되는데, 여기에서 리스트뷰의
멤버함수인 CustomSort()를 호출해주면 됩니다.

이 CustomSort()함수가 실제로 호출되는 방법은 조금 복잡해지는데, 만약 CustomSort()의
첫번째 인자로 소트를 실제로 할 함수를 지정해주면 그 함수가 실행됩니다.
이 첫번째 인자로 NULL을 넘겨주면, 리스트뷰의 기본 소트 알고리즘이 실행되는데,
이것도 자세히 살펴보면 리스트뷰의 OnCompare 이벤트에 핸들러가 있을 경우 이 핸들러가
실행되며, 만약 핸들러가 없을 경우에는 가장 기본적인 소트 메소드인 AlphaSort()가 실행됩니다.

이 AlphaSort()는 말그대로 '기본적인' 소팅만을 하는데, 리스트뷰의 첫번째 컬럼,
즉 각 리스트뷰 아이템의 캡션만을 대상으로 소트하며, 또 역순으로 정렬할 수도 없으므로
이걸 그대로 써서 원하시는 동작을 하게 할 수는 없습니다.

앞에서 말했던 첫번째 방법, 그러니까 CustomSort()에서 소트할 함수를 지정해주고
그 함수에서 정렬을 하려고 하면 조금 복잡합니다. 왜냐하면 여기서 지정해주는
함수의 인자들의 형은 TListItem을 넘겨받기에는 좀 불편하기 때문이죠. 그래서
제가 권하고 싶은 방법은 OnCompare를 사용하는 것입니다.
먼저 간단한 소스를 보여드리죠.

void __fastcall TForm1::ListView1ColumnClick(TObject *Sender, TListColumn *Column)
{
    ListView1->CustomSort(NULL, Column->Index);
}

void __fastcall TForm1::ListView1Compare(TObject *Sender, TListItem *Item1,
      TListItem *Item2, int Data, int &Compare)
{
    if(Data == 0)
    {
         if(Item1->Caption < Item2->Caption) Compare = -1;
         else if(Item1->Caption > Item2->Caption) Compare = 1;
         else Compare = 0;
    }
    else
    {
         if(Item1->SubItems->Strings[Data-1] < Item2->SubItems->Strings[Data-1]) Compare = -1;
         else if(Item1->SubItems->Strings[Data-1] > Item2->SubItems->Strings[Data-1]) Compare = 1;
         else Compare = 0;
    }
}

위 소스를 일일이 설명드리자면 머리가 좀 아프고, 간단히 OnCompare 이벤트의
동작을 살펴보면, 첫 인자와 두번째 인자인 두 리스트아이템을 핸들러 내에서
맘대로 비교해서(프로그래머가 원하는 방식으로 비교하면 되는겁니다. 일반적으로는
알파벳순이나 숫자로 컨버트했을 때의 값의 크기가 기준이 되겠죠) 그 결과를 Compare로 돌려주면
되는 겁니다. 두 아이템을 비교한 결과에 따라서 Compare에 돌려주는 결과는 0보다 적은 값,
0, 0보다 큰 값으로 구분해서 넘겨줍니다. 여기서 Data 인자는 위의 첫번째 핸들러인
ListView1ColumnClick()에서 CustomSort()의 두번째 인자로 넘겨준 값이 그대로
넘어옵니다. 제가 작성한 위 코드에서는 컬럼의 인덱스를 넘겨줬으니 ListView1Compare()의
Data 인자로 클릭한 컬럼의 인덱스가 넘어오는 것입니다.

위 소스는 잘 동작하지만, 완벽하다고 생각하기에는 한가지 부족한 점이 있습니다.
그것은 역순 정렬이 안된다는 것입니다. 탐색기 등에서 컬럼을 클릭해보면, 이미 정렬이 된
상태에서 다시 한번 컬럼을 클릭하면 역순 정렬이 되는 것을 볼 수 있습니다.
그래서.. 역순 정렬이 되도록 다시 코드를 수정한 소스는 다음과 같습니다.
(조금더 복잡해지는 것은 어쩔 수 없겠지요?)

int SortByColumn = -1;                                  //
int SortOrder = 1;                                      //

void __fastcall TForm1::ListView1ColumnClick(TObject *Sender, TListColumn *Column)
{
    if(SortByColumn == Column->Index) SortOrder *= -1;  //
    else SortOrder = 1;                                 //
    ListView1->CustomSort(NULL, Column->Index);
    SortByColumn = Column->Index;                       //
}

void __fastcall TForm1::ListView1Compare(TObject *Sender, TListItem *Item1,
      TListItem *Item2, int Data, int &Compare)
{
    if(Data == 0)
    {
        if(Item1->Caption < Item2->Caption) Compare = -1;
        else if(Item1->Caption > Item2->Caption) Compare = 1;
        else Compare = 0;
    }
    else
    {
        if(Item1->SubItems->Strings[Data-1] < Item2->SubItems->Strings[Data-1]) Compare = -1;
        else if(Item1->SubItems->Strings[Data-1] > Item2->SubItems->Strings[Data-1]) Compare = 1;
        else Compare = 0;
    }
    Compare *= SortOrder;                               //
}

보시면 아시겠지만, 위의 역순 소트가 되지 않는 소스와 비교하여 추가된 라인에
주석 표시로 // 를 달아뒀습니다. 일일이 설명하기에는 설명이 너무 길어지겠고,
추가된 부분을 잘 분석해보시면 어떻게 동작하는지 아실 수 있을 겁니다.

위의 소스는 잘 동작하지만.. 무조건 알파벳 순 소팅만 합니다. 만약 컬럼의 내용이
문자열이 아닌 숫자라면, 당연히 값 위주로 정렬을 해야겠지요? 알파벳 순이 값 순서와
같은 기준이면 좋겠지만, 불행히도 그렇지 않습니다. 923, 9234 두 값을 비교하면,
알파벳 순 소트에서는 9234가 앞이지만 값 순이면 923이 앞입니다.
그러므로 컬럼의 값이 숫자일 때는 OnCompare에서 별도로 처리해주어야 합니다.

+ -

관련 글 리스트
12 [TECHNIQUE][COMPONENT] 리스트뷰에서 컬럼클릭했을때 정렬 박지훈.임프 19124 2000/06/13
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.