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

C++빌더 Q&A
C++Builder Programming Q&A
[1827] Re:[질문] 리스트뷰에서 컬럼클릭했을때 정렬...
박지훈.임프 [cbuilder] 4201 읽음    1999-08-23 00:00
: 안녕하세요?
: 리스트뷰에 대해서 질문을 드립니다.
: 마이크로소프트의 OutLook에 주소록이 있습니다.
: 이 주소록을 실행시켜 보면, 리스트뷰에 사람이름과
: 그에 해당하는 내용들이 나옵니다.
: 리스트 뷰의 컬럼중에 이름이라고 써있는 부분을 클릭
: 하면 이름순서대로 정렬됩니다. 또 전화번호라고 써있는
: 컬럼을 클릭하면 전화번호 순서대로 정렬됩니다.
: 이렇게 컬럼을 클릭하여  그에 해당하는 내용대로 정렬되는
: 것은 다른 프로그램에서도 볼수가 있습니다.
: 예를 들면, WinRar이나 WinZip같은 프로그램에서 말이죠..
: 어떡게 제 프로그램에서 이런방법으로 리스트뷰의 내용을
: 정렬 시키는 방법을 알고 싶습니다.
: 그럼 안녕히 계세요^^
:
:                     박세율올림



임펠리테리입니다.

리스트뷰의 컬럼을 클릭했을때 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에서 별도로 처리해주어야 합니다.

그럼 참고하시길...

+ -

관련 글 리스트
1825 [질문] 리스트뷰에서 컬럼클릭했을때 정렬... 박세율 3488 1999/08/23
1827     Re:[질문] 리스트뷰에서 컬럼클릭했을때 정렬... 박지훈.임프 4201 1999/08/23
1833         Re:Re:[질문] 리스트뷰에서 컬럼클릭했을때 정렬... 박세율 3543 1999/08/24
1834             Re:Re:Re:[질문] 리스트뷰에서 컬럼클릭했을때 정렬... 박지훈.임프 3600 1999/08/24
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.