티스토리 뷰

MFC CListCtrl

CListCtrl
리스크 컨트롤을 직접 다룰 수 있는 클래스

- CListView
리스크 컨트롤을 이용해서 구현한 뷰 클래스

1. 리스트 컨트롤 = 리스트 뷰 컨트롤

이미지와 텍스트를 이용하여 다양한 형태로 정보를 표시하는 역활을 한다.

- 작은 아이콘 보기 (Small Icon View)
- 목록 보기 (List View)
- 보고서 보기 (Report View)

16*16 크기의 아이콘과 텍스트로 각 항목을 표시하며, 항목 오른쪽 열에 서브 항목이 있어서 부가적인 정보를 텍스트로 표시한다. 제일 위쪽에는 헤더(Header) 컨트롤이 있어서 각 열의 폭을 조절할 수 있으며, 헤더를 클릭하면 해당 열을 기준으로 항목을 정렬할 수 있다.

텍스트만을 표시하는 경우가 아니라면 하나의 항목에 대해 최소 두 종류의 이미지를 필요로 한다.
단지 아이콘 보기와 그 밖의 보기에서 사용할 큰 이미지와 작은 이미지를 제공하면 된다.

- 리스트 컨트롤 스타일

View
리스트 컨트롤을 표시하는 방법을 나타내며 Icon, Small Icon, List, Report 중 하나를 선택한다.

Align (아이콘 보기, 작은 아이콘 보기에서만 유효)
Top : 항목을 표시할때 위쪽부터 차례로 채운다.
Left : 왼쪽 열부터 치례로 채운다.

Single Selection
마우스로 하나의 항목만 선택할 수 있도록 한다. 이 스타일을 설정하지 않을 경우 마우스와 키보드(Ctrl, Shift)를 이용하여 여러개의 항목을 선택할 수 있다.

Auto arrange
아이콘 보기와 작은 아이콘 보기에서 항목이 자동으로 정렬된다.

No label wrap
아이콘 보기에서 텍스트를 한 줄로 표시한다. 이 스타일을 설정하지 않을 경우 텍스크가 길면 여러 줄로 표시한다.

Edit labels
텍스트(레이블)를 곧바로 수정할 수 있도록 한다.

No scroll
항목의 개수가 많아 화면에 모두 표시할 수 없는 경우에도 스크롤바가 나타나지 않도록 한다. 이 경우 리스크 컨트롤의 크기를 잘 조정하여 모든 항목이 화면에 표시될 수 있도록 해야한다.

No colimun header
보고서 보기에서 제일 위쪽에 헤더가 표시되지 않도록 한다.

No sort header
헤더를 마우스로 클릭할 수 없도록 한다. 따라서 이 스타일을 설정하면 보고서 보기에서 헤더를 클릭함으로써 항목 정렬하는 등의 작업을 할 수 없다.

Show selection always
리스트 컨트롤이 키보드 포커스를 잃더라도 선택된 항목이 계속 반전된 상태로 남아있도록 한다.

Owner draw fixed
보고서 보기에서 부모 윈도우가 리스트 컨트롤 항옥을 직접 그린다. 이 경우 부모 윈도우는 WM_DRAWITEM 메시지를 처리해야 한다.

Owner data
기본적으로 리스트 컨트롤의 데이터는 컨트롤 자신이 관리한다. 그러나 이 스타일을 설정하면 실행 중에 부모 윈도우가 컨트롤이 필요로 하는 데이터를 공급한다. 이와 같은 리스트 컨트롤을 가상(Virtual) 리스트 컨트롤 이라 부르며, 데이터를 한쪽에서만 관리하므로 불필요한 메모리 낭비를 줄일 수 있어서 대량의 데이터를 리스트 컨트롤에 표시할때 적합하다.

Share image list
여러개 의 컨트롤이 하나의 이미지를 공유할 경우 이 스타일을 설정해야 한다. 그렇지 않으면 리스트 컨트롤이 파괴되면서 이미지 리스트로 파괴된다.

Border
컨트롤 주위에 경계선을 그린다.

여기까지는 표준 리스크 컨트롤 스타일(LVS_*) 또는 일반 윈도우 스타일(WS_*)에 해당된다. 이 밖에도 확장 리스크 컨트롤 스타일(LVS_EX_*)이 있는데 속성 대화상자로는 설정할 수 없지만, 실행 중에 스타일을 추가함으로써 시용할 수 있다. 확장 스타일은 COMCTRL32.DLL 의 버전에 따라 적용할 수 없는 경우도 있으므로 주의해야 한다.

1-1 리스트 컨트롤 클래스

대화상자가 아닌 일반 윈도우에 컨트롤 생성하고, 이미지와 텍스트를 모두 사용할때

A. CListCtrl 객체를 선언한 후 CListCtrl::Create()로 리스트 컨트롤을 생성한다.
B. CImageList객체를 선언한 후 CImageList::Create(), CImageList::Add() 등을 이용하여 이미지 리스트를 초기화한다.
C. CListCtrl::SetImageList()로 리스트 컨트롤에서 사용할 이미지 리스트를 설정한다.
D. CLIstCtrl::InsertColumn() 으로 보고서 보기에서 표시할 헤더를 초기화 한다.
E. CListCtrl::InsertItem() 으로 항목을 추가한다.
F. CListCtrl::SetItemText() 로 하위 항목을 채운다.

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
32
33
34
// A. CListCtrl 객체 선언과 리스트 컨트롤 생성
CListCtrl list;
list.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT, CRect(00300100), this, IDC_LIST1);
    
// B. CImageList 객체 선언과 이미지 리스트 초기화
CImageList ilLarge, ilSmall; 
ilLarge.Create(3232, ILC_COLOR4, 11);
ilSmall.Create(1616, ILC_COLOR4, 11);
ilLarge.Add(AfxGetApp()->LoadIconW(IDI_ICON1));
ilSmall.Add(AfxGetApp()->LoadIconW(IDI_ICON2));
 
// C. 이미지 리스트 설정
list.SetImageList(&ilLarge, LVSIL_NORMAL);
list.SetImageList(&ilSmall, LVSIL_SMALL);
ilLarge.Detach();
ilSmall.Detach();
 
// D. 헤더 초기화
list.InsertColumn(0,  L"이름", LVCFMT_LEFT, 100);
list.InsertColumn(1, L"성적", LVCFMT_LEFT, 100);
list.InsertColumn(2, L"학점", LVCFMT_LEFT, 100);
 
// E. 항목 추가
list.InsertItem(0, L"김철수"0);
list.InsertItem(1, L"이영희"0);
list.InsertItem(2, L"박선아"0);
 
// F. 하위 항목 추가
list.SetItemText(01, L"90");
list.SetItemText(02, L"A");
list.SetItemText(11, L"95");
list.SetItemText(12, L"A+");
list.SetItemText(21, L"70");
list.SetItemText(22, L"B0");
cs

- CListCtrl 객채 선언과 리스트 컨트롤 생성

BOOL CListCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);

dwStyle : 컨트롤 스타일을 지정하며, 일반 윈도우 스타일(WS_*)과 리스트 컨트롤 스타일(LVS_*)의 조합을 사용한다. WS_CHILD, WS_VISIBLE, WS_BORDER 스타일은 거의 필수이며, LVS_REPORT 스타일은 보고서 보기로 리스트 컨트롤을 생성한다.

rect : 컨트롤의 크기와 위치를 지정하며 RECT 또는 CRect 객체를 사용한다.

pParentWnd : 부모 윈도우를 나타낸다.

nID : 컨트롤 ID

- CImageList 객체 선언과 이미지 리스트 초기화

이미지 리스트 생성과 초기화 부분이며 이미지 리스트 참고한다. http://petra.tistory.com/956

- 이미지 리스트 설정

CImageList* CListCtrl::SetImageList(CImageList* pImageList, int nImageListType);

pImageList : 리스트 컨트롤에서 사용할 이미지 리스트를 나타낸다.
nImageListType : 이미지 리스트에 포함된 이미지의 용도를 나타낸다.

<nImageListType>

nImageListType 

 용도 

 LVSIL_NORMAL 

 아이콘 보기 

 LVSIL_SMALL 

 작은 아이콘 보기, 목록 보기, 보고서 보기 

 LVSIL_STATE 

 상태 이미지 

- 헤더 초기화

int CListCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat=LVCFMT_LEFT, int nWidth=-1, int nSubItem=-1);

nCol : 열 번호를 나타내며 0부터 시작한다.
lpszColumnHeading : 헤더 컨트롤레 표시할 텍스트
nForamt : 헤더 컨트롤에 표시할 텍스트의 정렬 방식을 나타내며 LVCFMT_LEFT, LVCFMT_RIGHT, LVCFMT_CENTER 중 하나를 선택하면 된다.
nWidth ; 열의 폭을 나타내며 픽셀 단위를 사용한다.
nSubItem : 연관된 하위 항목의 인덱스를 나타내며, 보통 nCol과 같은 값을 사용한다.

- 항목 추가

int CListCtrl::InsertItem(int nItem, LPCTSTR lpszItem, int nImage);

nItem : 항목 인덱스이며 0부터 시작한다.
lpszItem : 항목에 표시할 텍스트
nImage : 항목에 표시할 이미지로서 이미지 리스트의 인덱스 값을 사용한다.

- 하위 항목 추가

BOOL CListCtrl::SetItemText(int nItem, int nSubItem, LPCTSTR lpszText);

nItem : 항목 인덱스이며 0부터 시작한다.
nSubItem : 하위 항목 인덱스이며 1부터 시작한다. 0을 사용하면 항목 텍스트를 바꿀 수 있다.
lpszText : 하위 항목(nSubItem > 0) 또는 항목(nSubItem = 0)에 표시할 텍스트

- 스타일 변경하기

LVS_* 형태의 표준 리스트 컨트롤 스타일 변경

BOOL CWnd::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags=0);

dwRemove : 제거할 스타일
dwAdd : 추가할 스타일
스타일을 변경한 후 nFlags의 값에 따라 컨트롤의 위치나 크기를 바꿀 수 있는데 특별한 경우가 아니라면 기본값을 사용하면 된다.

1
2
list.ModifyStyle(LVS_TYPEMASK, LVS_ICON); // 아이콘 보기로 변경한다.
list.ModifyStyle(0, LVS_EDITABLES); // 레이블 편집 가능하게 한다.
cs

리스트 컨트롤의 보기 스타일을 변경하는 경우 dwRemove에는 반드시 LVS_TYPEMASK 를 사용해야 한다.

LVS_EX_* 형태의 확장 리스트 컨트롤 스타일 변경

DWORD  CListCtrl::SetExtendedStyle(DWORD dwNewStyle);

dwNewStyle : 새로 적용할 확장 스타일
기존의 확장 스타일을 유지하려면 CListCtrl::GetExtendedStyle() 의 리턴값과 새로 추가할 확장 스타일을 조합해서 사용해야 한다. (헤더 추가하는 코드에서 구현하면 된다)

1
2
3
4
// 보고서 보기에서 격자 무늬를 표시
m_list.SetExtendedStyle(list.GetExtendedStyle() | LVS_EX_GRIDLINES);
// 보고서 보기에서 항고 선택 시 줄 전체 선택 
m_list.SetExtendedStyle(list.GetExtendedStyle() | LVS_EX_FULLROWSELECT); 
cs

 (리스트뷰 로 만든 프로젝트)

 

- 선택 항목 알아내기

A. 마우스 또는 키보드로 새로운 항목을 선택한 경우
B. 마우스로 항목을 더블 클릭한 경우
C. 선택된 여러개의 항목을 조사하는 경우 (특정 시점에 선택사항을 알아내는 경우)

A-1. 마우스 또는 키보드로 새로운 항목 선택한 경우

WM_NOTIFY 통지 메시지가 발생하며 통지 코드는 LVN_ITEMCHANGED 이다.
통지 코드와 더불어 NMLISTVIEW 구조체 포인터가 전달된다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct tagNMLISTVIEW
{
    NMHDR   hdr;
    int     iItem; // 선택한 인덱스
    int     iSubItem;
    UINT    uNewState; // 항목의 새로운 상태 
        // 항목이 새로 선택되면 LVIS_SELECTED, LVIS_FOCUSED 두 값의 조합이 된다.
 
    UINT    uOldState; // 항목의 이전 상태로 LVIS_* 값의 조합         
    UINT    uChanged; // 항목의 속성중 어느것이 변경되었는지 나타냄 
        // LVIF_* 조합, 상태가 변경되면 uChanged & LVIF_STATE 값이 TRUE 가 된다.
 
    POINT   ptAction;
    LPARAM  lParam;
} NMLISTVIEW, *LPNMLISTVIEW;
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BEGIN_MESSAGE_MAP(CMFCApplication16View, CListView)
    ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, &CMFCApplication16View::OnLvnItemchanged)
END_MESSAGE_MAP()
 
void CMFCApplication16View::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
    if (pNMLV->uChanged & LVIF_STATE && pNMLV->uNewState & LVIS_SELECTED) // 상태가 변경되었는지 검사
    {
        CString str = m_list.GetItemText(pNMLV->iItem, 0);
        AfxGetMainWnd()->SetWindowTextW(str);
    }
    *pResult = 0;
}
cs

A-2. 마우스로 항목을 더블 클릭한 경우

WM_NOTIFY 통지 메시지가 발생하며 통지 코드는 NM_DBLCLK 이다.
이때 NMITEMACTIVATE 구조체 포인터도 같이 전달된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef struct tagNMITEMACTIVATE
{
    NMHDR   hdr;
    int     iItem; // 선택한 항목의 인덱스 값, 하위 항목 또는 그 밖의 다른곳을 선택하면 -1
       // iItem 값을 검사하면 선택된 항목을 알 수 있다.
 
    int     iSubItem;
    UINT    uNewState;
    UINT    uOldState;
    UINT    uChanged;
    POINT   ptAction;
    LPARAM  lParam;
    UINT    uKeyFlags; // Alt, Ctrl, Shift 키 상태값
} NMITEMACTIVATE, *LPNMITEMACTIVATE;
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BEGIN_MESSAGE_MAP(CMFCApplication16View, CListView)
    ON_NOTIFY_REFLECT(NM_DBLCLK, &CMFCApplication16View::OnNMDblclk)
END_MESSAGE_MAP()
 
void CMFCApplication16View::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
    if (pNMItemActivate->iItem != -1)
    {
        CString str = m_list.GetItemText(pNMItemActivate->iItem, 0);
        MessageBox(str);
    }
    *pResult = 0;
}
cs

A-3. 선택된 여러 개의 항목을 조사하는 경우

CListCtrl::GetFirstSelectedItemPosition(), CListCtrl::GetNextSelectedItem() 2개의 함수를 이용하면 선택한 항목 인덱스를 모두 알아 낼 수 있다.

1
2
3
4
5
6
7
POSITION pos = m_list.GetFirstSelectedItemPosition();
int nItem;
while (pos)
{
    nItem = m_list.GetNextSelectedItem(pos);
    TRACE(L"항목 %d번이 선택되엇습니다.\n", nItem);
}
cs

- 항목의 추가와 삭제

1
2
3
m_list.InsertItem(...); // 항목 추가
m_list.DeleteItem(); // 1개 항목 삭제
m_list.DeleteAllItems(); // 모든 항목 삭제
cs

추가>
// 현재 스크롤 위치 추출
int iScrollPos = listctrl.GetScrollPos(SB_VERT);

 
// 작업 코드
........
// 리스트의 현재 행 추출
int iNum(-1);
POSITION pos = listctrl.GetFirstSelectedItemPosition();
iNum =  listctrl.GetNextSelectedItem(pos);
........
 
// 스크롤 움직이기
CRect ref;
listctrl.GetItemRect(0,ref,LVIR_BOUNDS);
CSize szHeight(0,ref.Height() * iScrollPos);
listctrl.Scroll(szHeight);           
listctrl.SetScrollPos(SB_VERT, iScrollPos, FALSE);
 
// 현재 행 선택
if(iNum >= 0)
{
// 먼저 현재 선택상태를 해제합니다
m_list_Immun_Buff.SetItemState( -1, 0, LVIS_SELECTED|LVIS_FOCUSED );
// 원하는 아이템을 선택합니다
m_list_Immun_Buff.SetItemState(iNum, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
// 선택된 아이템을 표시합니다
m_list_Immun_Buff.EnsureVisible(iNum, false);
// 리스트 컨트롤에 포커스를 맞춥니다
m_list_Immun_Buff.SetFocus();
}

추가2>

 스크롤바로 이동 후 화면 갱신할때 스크롤 위치로 이동시켜준다. (스크롤바가 움직여 화면 깜박임 문제 발생)

1
2
3
4
5
6
7
8
//////////////////
// CListCtrl 항목을 전체 지우기 전에 스크롤바 위치값을 저장한 iScrollPos 를 이용해서 해당위치로 스크롤 하기
CRect ref;
m_ListCtrl.GetItemRect(0, ref, LVIR_BOUNDS);
CSize szHeight(0, ref.Height() * iScrollPos);
m_ListCtrl.Scroll(szHeight);
m_ListCtrl.SetScrollPos(SB_VERT, iScrollPos, FALSE);
//////////////////
cs
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
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