2010년 10월 22일 금요일

[리스트박스-기초02] 아이템의 추가/삽입/삭제/선택

리스트 박스를 사용하면서 주로 쓰이는 기능이 대표적으로 아이템의 추가, 삽입, 삭제 및 선택 기능이다. 기능은 단순하지만, 리스트 박스의 속성에 따라 동작 특성이나 메서드의 응답이 달라진다.

아래의 함수는 리스트박스에 긴 문자열이 들어갔을 경우, 수평 스크롤바를 생성시키는 코드이다.
이전 장에서 다룬것을 조금 확장한 것이고, 앞으로 리스트박스에서 항상 쓰일 함수이다.

static int GetTextLenEx(CListBox& box, LPCTSTR lpszText)
{
    CSize size;
    CDC *pDC = box.GetDC();
   
    CFont* pOld = pDC->SelectObject(box.GetFont());
    if ((box.GetStyle() & LBS_USETABSTOPS) == 0)
    {
        size = pDC->GetTextExtent(lpszText, _tcslen(lpszText));
        size.cx += 3;
    }
    else
    {
        size = pDC->GetTabbedTextExtent(lpszText, _tcslen(lpszText), 0, NULL);
        size.cx += 2;
    }
    pDC->SelectObject(pOld);
    box.ReleaseDC(pDC);
   
    return size.cx;
}

static void AddStringEx(CListBox& box, CString str, int ndx = -1)
{
    if(ndx == -1)
        box.AddString(str);
    else
        box.InsertString(ndx+1, str);

    int iExt = GetTextLenEx(box, str);
    if (iExt > box.GetHorizontalExtent())
        box.SetHorizontalExtent(iExt);
}


우선 리스트 박스 하나를 single 선택 모드로 예제를 하나 작성하였다.
리스트 박스를 선택할 때 속성에 따라 동작이 다름에 주의하여야 한다.

각각의 기능을 구현한 함수는 다음과 같다.

void CSssDlg::OnButton1()
{
    AddStringEx(m_list, "하나");  AddStringEx(m_list, "둘");
    AddStringEx(m_list, "셋");     AddStringEx(m_list, "넷");
    AddStringEx(m_list, "다섯");  AddStringEx(m_list, "여섯");
    AddStringEx(m_list, "일곱");  AddStringEx(m_list, "여덟");
    AddStringEx(m_list, "아홉");  AddStringEx(m_list, "임의의 아이템을 10개를 리스트 박스에 삽입함.");
}

void CSssDlg::OnButton2()
{
    UpdateData(TRUE);
    AddStringEx(m_list, m_str_insert, m_list.GetCurSel());
}

void CSssDlg::OnButton3()
{
    UpdateData(TRUE);
 
    m_list.SetCurSel(m_sel_program);
}

void CSssDlg::OnButton4()
{
    m_list.DeleteString(m_list.GetCurSel());
}

void CSssDlg::OnButton5()
{
    m_list.ResetContent();
}
single 선택 모드일 경우는 아이템을 하나씩만 선택할 수 있기 때문에, 선택이나 삭제가
위처럼 수월하게 이루어진다.







하지만 multiple나 extended 로 다중 선택할 경우.. GetCurSel의 응답이 약간 달라진다.
single
   아이템이 선택되었을 경우 : 선택된 아이템의 인덱스
   아이템이 선택되어지지 않았을 경우 : -1
multiple or extended
   아이템이 선택되었을 경우 : 최종 선택된 아이템의 인덱스
   아이템이 선택되어지지 않았을 경우 : 0

일단 다중 선택이 가능한 상태에서 그럼 어떻게 여러개의 아이템이 선택되어 졌는지를
인식하고, 그 항목들을 가져 올 수 있는지 살펴보자.

void DoSomething(CListBox& box)
{
    // 몇개의 아이템이 선택되어졌는지 카운트
    int nCount = box.GetSelCount();

    // 선택되어진 아이템이 하나도 없으면 리턴.
    if(nCount <= 0)
        return;
   
    // 배열을 하나 만들고, 크기를 설정한다.
    CArray<int,int> aryListBoxSel;
    aryListBoxSel.SetSize(nCount);

    // 아이템중에서 선택되어진 인덱스를 배열에 읽어온다.
    box.GetSelItems(nCount, aryListBoxSel.GetData());

    for(int i=0; i<nCount; i++)
    {
         // 선택된걸 하나씩 뽑아서 먼가 처리를 하겠지...
         int sel = aryListBoxSel[i];
   
        // do something... 
    }
}

위의 함수에서 보았듯이 여러개의 아이템이 선택되어져 있을 경우, 먼저 선택 아이템 카운트를
읽어온다음, 그 인덱스를 배열에 읽어오는 과정을 거친다.

그럼 다중 선택일 경우에 선택아이템을 지우는 버튼의 코드를 수정해보자.

싱글 선택일 경우는 아래와 같았다.
void CSssDlg::OnButton4()
{
    m_list.DeleteString(m_list.GetCurSel());
}

멀티 선택일 경우는 다음과 같다.
void CSssDlg::OnButton4()
{
    int nCount = box.GetSelCount();
    if(nCount <= 0)
        return;
   
    CArray<int,int> aryListBoxSel;
    aryListBoxSel.SetSize(nCount);
    box.GetSelItems(nCount, aryListBoxSel.GetData());

    // 앞에꺼 부터 지우게 되면 뒤쪽의 저장해 놓은 인덱스 정보가 틀어지게 되므로
    // 뒤에꺼 부터 앞으로 하나씩 지우면 된다.

    for(int i=nCount-1; i>=0; i--)
          m_list.DeleteString(aryListBoxSel[i]);
}

댓글 없음:

댓글 쓰기