오늘은 Windows라는 운영체제가 GUI 프로그래밍 용도로 제공하는 공용 컨트롤들 중의 하나인 리스트뷰(List-view) 컨트롤에 대해 자세히 알아보도록 하겠다. (이름에서 '뷰'는 종종 생략되기도 함)
결론부터 말하자면 얘는 정말 세심하게 설계된 다재다능한 요물이다. 동일한 규격을 가진 다수의 아이템들, 특히 그림과 글자가 같이 가미된 아이템을 표시하는 모든 방식과 가능성을 고려해서 만들어졌다. 그래서 정말 많은 기능들을 제공한다.

리스트뷰가 기존의 재래식 초간단 리스트박스와 다른 점은 다음과 같다.

  • 리스트뷰는 글자뿐만 아니라 곁들여진 그림도 태생적으로 같이 처리 가능하다. 리스트박스에서는 그림과 글자를 같이 표시하기 위해서 얄짤없이 owner-draw로 가야 했다.
  • 마우스의 동작이 다르다. 리스트박스는 내부를 왼쪽 버튼으로 아이템을 선택해서 드래그 하면 선택막대가 자동으로 쭉 바뀌며 스크롤도 된다. 하지만 리스트뷰는 그렇지 않다.
  • 키보드의 동작도 다르다. 아이템을 복수 선택할 때 리스트뷰는 Ctrl+화살표를 눌러서 포커스만 이동시키고 Ctrl+Space로 선택을 하지만 리스트박스는 Shift+F8과 space 같은 다른 글쇠를 사용한다. 리스트뷰는 F2를 눌러서 아이템의 이름을 바꾸는 기능도 있지만 리스트박스는 그렇지 않다.

아울러, 리스트뷰가 같이 추가된 공용 컨트롤인 트리뷰(Tree-view) 컨트롤과 다른 점은 다음과 같다.

  • 트리는 아이템 하나를 HTREEITEM이라는 별도의 자료형으로 식별하지만, 리스트는 그냥 인덱스 번호이다. 트리는 노드 포인터 기반의 이산적인 컨테이너를 쓰지만, 리스트는 내부적으로 배열과 유사한 컨테이너를 쓰는 듯하다.
  • 리스트는 아이템의 복수 선택이 가능하지만 트리는 그렇지 않다.
  • 트리는 리스트와 같은 다양한 view 모드가 존재하지 않는다.
  • 아이템의 텍스트를 진하게 표시하는 state 플래그가 트리에는 있지만 리스트에는 없다.

리스트박스와 위상이 비슷한 자매 컨트롤(?)은 콤보박스이다. 하지만 리스트뷰와 위상이 비슷한 자매 컨트롤은 트리뷰라고 할 수 있다.
왼쪽에 트리뷰, 오른쪽에 리스트뷰를 배치한 프로그램으로는 탐색기, 레지스트리 편집기, 시스템 정보 등 의외로 꽤 많다. 왼쪽에서 카테고리를 선택하면 오른쪽에서 세부 정보가 표시되는 것이다. 오죽했으면 Visual C++의 MFC 프로젝트 마법사에도 요런 형태의 프로그램을 만드는 템플릿이 제공될 정도이다.

옛날에는 리스트박스를 서브클래싱 해서 drag & drop을 구현하고, owner-draw와 item data를 이용해서 얼추 트리 계층 구조라든가 check list를 구현하고, 파일이나 디렉터리나 드라이브 목록을 채워 주는 리스트를 만드는 등.. 별별 짓을 다 했다. 그리고 Visual Basic 부류의 RAD 툴들은 그걸 미리 구현해 놓은 리스트를 컴포넌트 형태로 제공했었다. 하지만 리스트뷰와 트리뷰 공용 컨트롤이 등장하면서 리스트박스의 역할이 상당수 분담되었다.

Windows 탐색기의 보기 메뉴에서 보는 바와 같이 리스트뷰 컨트롤에는 다양한 보기 모드가 있다.

(1) 큰 아이콘
아이콘이 중심이고 이를 설명하는 주 텍스트가 아이콘의 하단 중앙에 찍힌다. 이걸로 끝. 아이콘의 크기는 무엇이 되어도 상관없지만 보통은 표준 아이콘 크기인 32*32 또는 그보다 약간 더 큰 48*48이 쓰인다.
탐색기에서 확대 배율 조정이 되는 대부분의 모드들은 이 모드에 속한다. 아이콘의 크기만 바꾸는 거니까.. (보통 아이콘, 큰 아이콘, 아주 큰 아이콘..) 또한 당장 바탕 화면에 표시된 아이콘들도 다 리스트뷰의 이 모드인 것을 알 수 있다.

사용자 삽입 이미지

(2) 작은 아이콘
글자의 크기와 대등한 크기인 작은 아이콘이 쓰이며, 아이콘의 아래가 아니라 오른쪽에 주 텍스트가 나란히 찍힌다.

사용자 삽입 이미지

(3) 목록
아이템 하나가 표시된 모습이 작은 아이콘 모드와 완전히 동일하다. 그렇기 때문에 '작은 아이콘'과 차이가 무엇인지 언뜻 봐서는 구분하기 어렵다. 하지만 작은 아이콘(+ 큰 아이콘도 포함)에서는, 아이템을 드래그 해서 화면의 아무 위치로나 옮길 수가 있는 반면, 목록 모드는 그렇지 않다. i째 아이템은 현재의 스크롤 위치 기준으로 반드시 그에 상응하는 위치에 있어야 하며, 아무 위치로나 옮길 수 없다.

사용자 삽입 이미지

(4) 자세히(일명 report view)
한 줄에 아이템이 오로지 하나만 찍힌다. 작은 아이콘, 주 텍스트, 그 다음으로 n개의 부 텍스트가 마치 표처럼 일목요연하게 표시된다. 즉, 이 모드는 부 텍스트를 표 형태로 모두 볼 수 있는 유일한 모드이며, 상단에 헤더 컨트롤이 등장해서 쓰이는 유일한 모드이기도 하다.

사용자 삽입 이미지

사실, 헤더 컨트롤만 별도로 따로 생성할 수도 있다. 얘만으로도 각종 메시지 스펙이 공개돼 있는 별개의 공용 컨트롤이기 때문이다.
하지만 우리가 아주 특수한 사연이 있어서 리스트뷰 컨트롤 같은 거창한 물건을 직접 자체 구현이라도 하지 않는 한, 헤더만 끄집어내서 사용할 일은 별로 없을 것 같다.

지금까지 소개한 4종류의 모드를 정리하자면, 아이콘 모드들은 align을 어찌 하느냐에 따라서 상하와 좌우 스크롤바를 모두 볼 수 있고, '목록' 모드는 좌우 스크롤바만 볼 수 있다.
'자세히' 모드는 개수가 초과될 때는 상하 스크롤바이고, 아이템을 표시하는 폭이 초과됐을 때만 좌우 스크롤바를 볼 수 있다.

그리고 아이콘 모드는 기존 리스트박스에는 전혀 없던 새로운 기능이며, 기존 리스트박스와 가장 비슷한 모드는 '자세히' 내지 '목록' 모드라는 것을 알 수 있다. 이 두 모드에서는 아이콘은 필수가 아닌 그냥 선택, 옵션이다. 기존 리스트박스처럼 그림 없이 글자를 출력하는 용도로만 써도 된다.

이들에 비해 '작은 아이콘' 모드는 정체성이 불분명해서 사실 잘 쓰이지 않는다. 아이콘을 강조하고 싶으면 '큰 아이콘'으로 가면 되고, 좀 더 예쁘게 일목요연하게 아이템들을 출력하려면 '목록'(간단히) 또는 '자세히'로 가면 되기 때문이다. 저 그림에서도 보다시피 작은 아이콘은 폭이 들쭉날쭉이어서 보기에도 별로 좋지 않다.

그래서 Windows XP에서는 제5의 새로운 모드가 추가됐다. 바로..

(5) 타일
큰 아이콘을 사용하는데, 주 텍스트는 아이콘의 아래가 아닌 오른쪽에 출력된다.
아이콘이 좀 큰 편이니 주 텍스트의 아래에도 여유 공간이 생기는데, 거기에는 부 텍스트 중에서 사용자가 지정한 것을 덤으로 출력해 준다.

사용자 삽입 이미지

이것도 굉장히 참신한 발상인 것 같다. 타일의 폭은 사용자가 임의로 지정 가능하다.
align은 아이콘 모드처럼 left와 top을 모두 지정 가능하다. 다만, 아이템들의 위치까지 아이콘 모드처럼 임의 지정 가능한지는 잘 모르겠다.

원래 리스트뷰 컨트롤의 보기 모드는 4종류이다 보니.. 윈도우 스타일에서 0부터 3까지 딱 2개의 최하위 비트를 사용하여 지정하게 돼 있었다.
컨트롤을 생성하고 아이템들을 잔뜩 추가한 뒤에도 모드를 변경할 수 있었다. SetWindowLongPtr을 이용해서 스타일 값을 변경하면 컨트롤이 이를 인식해서 모드를 변경했다.

그런데 제5의 모드는 이런 식으로 지정할 수 없게 됐다. 리스트뷰 컨트롤은 기능이 워낙 너무 많아서 스타일, 확장 스타일, 거기에다 자신만의 고유한 전용 확장 스타일까지(LVM_SETEXTENDEDLISTVIEWSTYLE) 비트 플래그들이 꽉 찼기 때문이다.
결국은 LVM_SETVIEW라고 보기 모드를 지정하는 전용 메시지가 추가됐다. 새로운 보기 모드를 겨우 하나 추가하기 위해서였다.

네이버나 다음의 블로그들만 들어가 봐도 제목 목록만 표시, 본문까지 약간 포함해서 타일 형태로 표시.. 처럼 적어도 두세 종류의 보기 모드가 있는 걸 알 수 있다. 리스트뷰도 그런 식으로 그림과 글자의 표시 비율, 아이템당 전체 크기 같은 다양한 변수를 이런 식으로 제어할 수 있다고 생각하면 된다.
아이콘이 들어갈 자리에 사람 얼굴이 들어가면 무슨 인사기록표나 선거 후보 목록을 출력할 수 있을 것이고, 한자가 들어가면 옥편· 자전 내용을 이런 식으로 출력할 수 있을 것이다.

그럼 이제부터는 리스트뷰 컨트롤의 주요 개념이나 기능에 대해서 분야별로 간단히 소개한 뒤 글을 맺도록 하겠다.

1. image list

리스트와 트리 컨트롤은 아이템들 옆에 출력할 다양한 종류의 아이콘 그림들을 한데 관리하기 위해서 무슨 HICON을 몇백 개 내부적으로 관리..하는 건 아니고 image list라는 자료 구조를 공통으로 사용한다. image list는 마치 애니메이션 프레임처럼 크기가 동일한 여러 그림들의 배열이라고 생각하면 되며, 아이콘 핸들도 물론 손쉽게 등록할 수 있다. 투명색은 이미지 내부의 특정 배경색 또는 별도의 마스크 비트맵 중 편한 것으로 지정 가능하다.

또한 트리에서는 작은 아이콘이라는 한 종류만 사용하지만, 리스트 컨트롤에서는 구조적으로 큰 아이콘, 작은 아이콘 두 종류를 나눠서 지정 가능하다.
그리고 한 아이템의 아이콘에 대해서 여러 종류의 이미지를 한데 겹쳐서(overlay) 지정할 수도 있다. 파일이라면 '바로가기'임을 나타내는 자그마한 화살표라든가, 버전 관리 시스템에서 Up-to-date, modified 같은 상태를 나타내는 자그마한 modifier 그림이 바로 아이콘 overlay를 이용해서 표시된 것이다.

2. 그룹 분류

Windows XP에서는 타일 모드에 이어 리스트뷰 컨트롤에 아주 획기적인 기능이 하나 추가됐는데, 바로 '그룹' 기능이다. 필요하다면 그룹 내지 카테고리라는 것을 등록해 놓은 뒤, 아이템들별로 소속 그룹을 지정하면 이것들이 그룹별로 분류되어 딱 일목요연하게 표시된다.

사용자 삽입 이미지

그룹이 처음으로 도입된 XP에서는 이것 말고 다른 기능은 없다. Vista에서는 그룹에 대해 [+], [-] 버튼을 눌러서 마치 트리 컨트롤처럼 collapse/expand이 되게 하는 기능이 추가되었다. 단, 응용 프로그램에서 그게 가능하도록 별도의 비트 플래그를 넣은 그룹에 대해서만 그렇게 동작한다.
그룹은 다른 보기 모드에서는 다 지원되고 '목록' 모드만 열외이다.

3. 수많은 기능과 복잡한 API

리스트뷰 컨트롤은 당장 마소에서도 적극 사용하고 있다 보니, 자기 필요에 따라서 이것저것 수많은 기능들이 추가돼 왔다.
특히 IE4 시절에는 Active 데스크톱이니 뭐니 하면서 뭐든지 웹페이지처럼 보이게 하는 게 유행이었다. 리스트뷰 컨트롤의 아이템을 클릭하는 것조차 밑줄 쳐진 링크를 클릭하는 것과 비슷하게 보이게 하는 옵션은.. 음~ 정말 비장함이 느껴진다.

리스트뷰는 기능이 너무 많고, 공용 컨트롤 특유의 그 조작감까지 더해져서 다루기가 귀찮고 까다롭다. 리스트박스처럼 간단하게 LB_ADDSTRING + "문자열" 한 방으로 아이템을 추가할 수 없다. 뭘 더하고 고치려면 기본적으로 LVITEM 구조체 선언하고 마스크 플래그 지정하고..

더구나 문자열 부분 멤버는 읽기 쓰기 겸용으로 모두 쓰인다. Set 용도로 읽기 전용 문자열 포인터를 집어넣으려 해도 부득이하게 PTSTR 멤버에다가 const_cast를 해 줘야 된다. PTSTR과 PCTSTR을 공용체로라도 좀 같이 넣어 주지 하는 아쉬운 생각이 든다.

그리고 아이템 drag & drop은 컨트롤에서 우리에게 이벤트만 날려 주고 그걸로 끝이다. 드래그용 이미지를 생성하고 마우스 포인터 모양을 바꾸고 실제로 drop 처리를 하는 것, 아이콘 모드의 경우 실제 위치를 변경하는 LVM_SETITEMPOSITION 요청 따위는... 머리부터 발끝까지 사용자가 전부 일일이 구현해야 한다. 이거 일이 여간 번거로운 게 아니다.

헤더 클릭 정렬도 마찬가지다. 컨트롤이 자동으로 해 주지 않는다. 클릭된 헤더에 대해서 오름차순/내림차순/무정렬 상태를 나타내는 ▲▼ 모양을 표시하는 것, 다른 헤더에 있던 마크는 제거하는 것까지 전부 미주알고주알 우리가 해 줘야 되며, 아이템 비교 함수도 우리가 공급해 줘야 한다.
좋게 말하면 customize의 폭이 큰 것이고 나쁘게 말하면.. 귀찮다. 물론 재래식 리스트박스는 한번 등록된 아이템은 텍스트를 고치거나 순서를 변경하는 기능 자체가 전무했으니 그것보다는 상황이 나아진 셈이다.

4. 시스템 색상 변경

어떤 윈도우가 WM_PAINT를 받아서 자기 내용을 그릴 때, 매번 GetSysColor나 GetSysColorBrush를 호출하고, 매번 색깔을 새로 지정하고 펜과 브러시를 새로 생성한다면.. 시스템 색상이 나중에 달라지더라도 별 상관 없다.
하지만 성능을 위해서 이런 GDI 개체를 보관해 놓는다거나, 특정 시스템 색상이 합성된 상태로 비트맵 같은 걸 저장하고 있다면(일종의 캐싱).. 그것들은 시스템 색상이 바뀌었을 때 갱신되어야 한다.

이 상태를 알리는 메시지가 바로 WM_SYSCOLORCHANGE이다. 이제는 macOS조차도 최신 10.14 '모하비'에서 Dark 테마가 추가되었으니 시스템 색상 변경과 비슷한 개념이 도입된 셈이다. Windows는 다른 색깔 테마들은 다 없어졌지만 고대비 블랙/화이트만이 특수한 용도로 남아 있다.

WM_SYSCOLORCHANGE는 top-level 윈도우들에게 전파된다. 차일드에 속하는 리스트뷰 컨트롤이 이 메시지를 직접 받지는 못한다. 아이콘을 사용하지 않을 때는 별 문제가 없는데, 아이콘을 사용하는 컨트롤에 대해서 이 메시지를 수동으로 전해 줘야 한다. 그리하지 않으면 화면 배경의 흑백이 바뀌어도 쟤는 그게 반영되지 않아서 색깔 배색이 어색해지더라.

색깔 변경 통지도 마치 클립보드의 내용 변경 통지처럼 원하는 윈도우가 신청하면 top/bottom 위상을 불문하고 직통으로 받을 수 있어야 하지 않나 싶다. 이렇게 부모 윈도우가 일일이 전해 줘야 하는 건 디자인상 문제가 있어 보인다.

5. Ctrl+휠 인식

리스트뷰 컨트롤 내부에서 마우스 휠이 굴러갔다면 그렇다면 창 내부를 스크롤 하면 된다. 즉, 자체적으로 처리하면 되고 굳이 부모 윈도우에게 알려 줄 필요가 없다.
하지만 Ctrl+휠은 화면 확대 배율을 변경하는 용도로 쓰이는 게 요즘 추세이다. 응용 프로그램마다 자기가 사용하는 리스트뷰에서 지원하고자 하는 모드가 다를 테니, 이를 운영체제에서 임의로 일괄적으로 자동 지원할 수는 없다.

결국 Ctrl+휠은 그냥 휠과는 달리 부모 윈도우로 통지해 주는 게 바람직해 보인다. 하지만 이와 관련된 event notification은 공식적으로 존재하지 않는다. 탐색기는 Ctrl+휠을 어떻게 구현했는지가 궁금해진다. 하긴, 탐색기는 리스트뷰 컨트롤도 워낙 많이 마개조했으니 윈도우 프로시저를 서브클래싱 해서 메시지 전체를 통째로 가로채 버렸다면 그 정도 구현쯤은 일도 아니긴 했을 것이다.

6. 체크리스트 모드에서의 버그

리스트뷰 컨트롤(그리고 트리 컨트롤도)에는 모든 항목들에 대해 체크박스를 넣는 옵션이 있다.
보통은 아이콘 자리에다가 체크박스 이미지를 집어넣는 꼼수를 동원해서 야메로 체크리스트 모드를 구현하는 편인데.. 이 옵션은 이미지와 별개로 체크박스를 또 표시해 준다.

이 기능은 공용 컨트롤이 처음 개발되던 때부터 있었던 건 아니고 Windows 98 + IE4 내지 5 타이밍 때 추가되었다. 이 기능이 처음부터 지원됐다면 리스트뷰 컨트롤의 Selection model이라는 속성 하에서 "단일 선택 / 체크박스 / 복수 선택" 중의 한 옵션으로 지원되는 게 바람직했을 것이다. 체크박스 모드에서 또 복수 선택을 사용할 일은 없을 테니까 말이다.

그리고 체크리스트 모드는 그 정의상 보기 모드들 중에서는 '목록' 모드와 가장 잘 어울리고 아니면 기껏해야 '자세히' 모드와도 추가로 어울린다. 큰 아이콘이 부각되는 모드와는 아무래도 영 어울리지 않는데, 그래도 원한다면 그 모드에서도 체크리스트를 사용할 수는 있다.
다만, 이 모드에서 키보드나 마우스로 체크 표시를 반복하면 선택막대가 갈수록 진해지는데.. 이건 명백히 버그로 보인다. 고전 테마나 XP~7 같은 구버전에서는 이런 현상이 없었고 Windows 8~10에서만 저런다!

사용자 삽입 이미지


Posted by 사무엘

2019/01/13 08:36 2019/01/13 08:36
, ,
Response
No Trackback , 3 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1575

Trackback URL : http://moogi.new21.org/tc/trackback/1575

Comments List

  1. 사포 2019/01/14 11:16 # M/D Reply Permalink

    윈도우 API들을 보다보면 초대형 프로젝트치고 정말 잘 설계했다고 느껴지는 부분이 많이 있더라구요. GUI 쪽도 그런 것 같아요.

    1. 사무엘 2019/01/14 13:03 # M/D Permalink

      네, 동감합니다. 뭐, 일부 지저분한 레거시, 첫단추를 좀 잘못 끼운 듯한 API 구조도 없지는 않지만.. Windows가 역사가 엄청 길고 레거시 지원이 정말 빵빵한 걸 감안하면 그 정도도 감지덕지이죠.
      사포 님, 오랜만에 뵙네요. 반갑습니다. ^^;;

  2. 사포 2019/01/16 10:24 # M/D Reply Permalink

    ㅎㅎ 오랜만이에용 새해 복 많이 받으세요 ^-^

Leave a comment

블로그 이미지

철도를 명절 때에나 떠오르는 4대 교통수단 중 하나로만 아는 것은, 예수님을 사대성인· 성인군자 중 하나로만 아는 것과 같다.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2019/01   »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Site Stats

Total hits:
1219376
Today:
67
Yesterday:
531