Issue
CListCtrl에 적은 수의 항목을 추가할 때는 CListCtrl에 항목이 바로 보여졌다. 그러나 6000개를 추가하려고하니 CListCtrl이 나타나는 속도가 느려졌다.
CListCtrl의 항목을 새롭게 업데이트하기 위해 InsertItem으로 항목을 하나하나 추가하는 방식이 느린 것이었다. 6000개를 모두 추가하고 show를 해주려고하니 느려질 수 밖에 없는 것이다.
Solution
CListCtrl의 Owner Data 속성을 True로 설정해준다. 이를 사용하면 6000개의 모든 항목을 List에 추가한 후 항목을 보여주는 것이 아닌, 사용자에게 보여지는 위치의 데이터만 스크롤 위치에 따라서 그때 그때 참조해서 보여주는 방식이다.
이 Owner Data방식에서는 InsertItem과 DeleteItem을 사용할 수 없다는 점을 유의해야한다.
1. Owner Data 속성을 True로 설정

2. CListCtrl에 추가할 item의 개수 설정
CListCtrl의 SetItemCountEx 함수로 뷰에 추가할 항목의 개수를 지정해줘야한다.
두번째 파라미터에 있는 옵션 설명은 MSDN에 있는 내용 가지고 온 것임.
- LVSICF_NOINVALIDATEALL:영향을 받는 항목이 현재 보기에 있지 않으면 목록 보기 컨트롤이 다시 그려지지 않습니다. 이것이 기본값입니다.
- LVSICF_NOSCROLL: 목록 보기 컨트롤은 항목 수가 변경될 때 스크롤 위치를 변경하지 않습니다.
list.SetItemCountEx(100, LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
3. LVN_GETDISPINFO 이벤트 처리함수로 데이터 Show
데이터는 스크롤 위치에 따라서 CListCtrl의 LVN_GETDISPINFO 이벤트 처리함수에서 Show해준다.

LVN_GETDISPINFO 이벤트 처리함수 코드
void MyDialog::OnLvnGetdispinfoListElsetNooderValue(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
LVITEM *pItem = &(pDispInfo)->item;
int iItem = pItem->iItem; //리스트의 row 번호
CString str;
if (pItem->mask & LVIF_TEXT) //valid text buffer? // 현재 업데이트할 셀에 TEXT를 입력할 수 있는 셀인지 확인
// 이 if 문이 없으면 에러났음
{
switch (pItem->iSubItem) { //리스트의 column 번호
case 0: //첫번째는 순서
str.Format(_T("%d"), iItem + 1);
_tcscpy_s(pItem->pszText, pItem->cchTextMax, str);
break;
case 1: //두번째는 데이터를 넣어준다.
str.Format(_T("%d"), arr[iItem]);
_tcscpy_s(pItem->pszText, pItem->cchTextMax, str);
break;
}
}
*pResult = 0;
}
내가 만들던 리스트는 아래와 같이 생겼다.

4. 스크롤이 움직이지 않으면 데이터가 변경되지 않는다. 스크롤을 움직이지 않아도 데이터를 업데이트 할 수 있도록 하는 방법
List의 스크롤을 움직이지 않고 내용을 변경하고 싶으면 List가 생성되어있는 클래스에서 Invalidate를 사용할 수 있다. Invalidate는 해당 클래스에 있는 모든 컨트롤윈도우들을 업데이트하는 것이기 때문에 깜빡임이 생길 수 있다.
그래서 Invalidate를 사용하지 않고 사용자에게 보여지는 항목만 업데이트 해줬다.
[방법1]
CListCtrl의 GetTopInex() 와 GetCountPerPage() 를 사용했다.
- GetTopIndex(): 현재 화면에 보여지는 최상위 아이템의 인덱스를 리턴한다.
- GetCounterPerPage(): 현재 보여지는 화면(Page)의 아이템 갯수를 리턴한다.
int iNum= list.GetTopIndex();
int viewSize = list.GetCountPerPage();
for (int i = iNum; i < list.GetItemCount() && i < iNum + viewSize; i++) list.Update(i);
[방법2]
위의 리스트 이미지를 보면 사용자에게 6개정도만 보여지므로 상단 일부만 업데이트 해줘도된다.
for(int i=0;i<10;i++) list.Update(i)
Review
MSDN을 찾아보는 것이 좋다는 글을 보고 MSDN을 찾아보니 방법이 생긴 것이었다.
역시 공식 문서가 해결책이라는 것을 한번더 느끼게 되었다.
6000개 보여질때 속도가 엄청 빠른거 보고 너무 감격... 이 뿌듯함에 개발하지 싶었다.
[Reference]
virtual list LVN_GETDISPINFO 알림 처리
: https://learn.microsoft.com/ko-kr/cpp/mfc/virtual-list-controls?view=msvc-170
코드 참고
:http://egloos.zum.com/manwooo/v/1410768
CListCtrl MSDN
: https://learn.microsoft.com/en-us/cpp/mfc/reference/clistctrl-class?view=msvc-170#update
GetTopIndex(), GetCountPerPage()
https://mins79.tistory.com/entry/속성-메서드-MFC-ListCtrl-예제
속성 메서드 ( MFC ListCtrl 예제 )
이전에 리스트 컨트롤을 이용한 간단한 샘플을 다루어 보았다. 이제 차근 차근 제공되는 메서드를 하나씩 알아가 보자. 전체를 다루기에는 MSDN이 울지 모르니 -_-;;;;; 주요 메서드만 다루어본다.
mins79.tistory.com
'◼️MFC' 카테고리의 다른 글
[MFC] 리소스 뷰에서 컴포넌트 최상단에 위치시키기 (0) | 2023.01.02 |
---|---|
[MFC] 다이얼로그 모달 방식 malloc 불가? (0) | 2022.10.11 |
[MFC] CListCtrl 팁 (0) | 2022.10.10 |
[MFC] 동적 메모리 할당한 구조체의 CString형 변수 에러 (0) | 2022.10.08 |
[MFC] CString 문자열 ( ) 속 문자열 추출 (0) | 2022.09.12 |