블로그 이미지
인생의무한루프
인생에 무한루프.....

calendar

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

Notice

Tag

Recent Post

Archive

Recent Comment

Recent Trackback

2008. 12. 17. 15:52 Appication/VC++_Control

동작 메서드 - InsertItem ( MFC ListCtrl 예제 )

InsertItem은 중요도도 높고, 다양한 양식을 제공함으로 별도로 취급한다.

1. int InsertItem(int nItem, LPCTSTR lpszItem);
2. int InsertItem(int nItem, LPCTSTR lpszItem, int nImage);
3. int InsertItem(const LVITEM* pItem);

샘플은 이전에 다루었던 장 중에서 하나씩 시작하기의 샘플을 수정하여 진행한다.
또한 LVITEM 구조체에 대한 설명은 링크를 참조한다.

1번과 2번에 대한 설명은 아이템의 인덱스, 레이블 문자열, 아이템의 이미지 인덱스와 같이
이해하기 쉽고 용법도 간단하므로 생략한다. (기존 장에서도 충분히 다루었다.)


아이템에 문자열만 넣기.
-----------------------------------------------------------------------------------
LVITEM item = {0};
item.mask = LVIF_TEXT;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
리스트컨트롤.InsertItem(&item);
아주 간단하게 해당 아이템의 인덱스에 문자열만을 넣어 보았다.
item.mask 값에 LVIF_TEXT 가 설정되었는데, 해당 문자열을 처리함을 알려준다.

이미 들어있는 아이템의 문자열을 변경하려면 SetItemText를 이용하여 변경이 가능하고
그 값을 가져오려면 GetItemText를 이용하면 된다.


아이템에 문자열과 이미지 넣기.
-----------------------------------------------------------------------------------
LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_IMAGE;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
item.iImage = 이미지 리스트의 해당 인덱스
리스트컨트롤.InsertItem(&item);
리스트 컨트롤에 이미지 리스트가 연결되어 있다면 LVIF_IMAGE 마스크를 넣어 이미리 리스트에해당하는 인덱스를 넣음으로써 컨트롤에 아이콘이 표시되도록 한다.

이미지 리스트를 연결하였음에도 불구하고, 이미지의 인덱스를 설정하지 않으면 기본값으로
0번 이미지가 그려짐에 주의하자.


한번 넣은 이미지를 변경하기 위한 별도의 메서드는 제공되지 않는다. 이미 넣은 이미지를
변경하기 위해서는 SetItem 메서드를 이용하여 변경이 가능하다.

예) 0번 아이템의 이미지를 5번 이미지로 바꾸기.

리스트컨트롤.SetItem(0, 0, LVIF_IMAGE, NULL, 5, 0, 0, 0);

LVITEM item = {0};
item.mask = LVIF_IMAGE;
item.iItem = 0;
item.iImage = 5;
리스트컨트롤.SetItem(&item);


아이템에 문자열과 부가 정보 넣기.
-----------------------------------------------------------------------------------
LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_PARAM;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
item.lParam = 4바이트 숫자형 데이터 or 부가정보의 포인터
리스트컨트롤.InsertItem(&item);
부가 정보 필드인 LVITEM::lParam은 LPARAM 타입의 변수로 기본타입은 long 이다.

초기 아이템 삽입시 저 정보의 설정이 불필요하고 나중에 설정하거나 가져오려면
SetItemData 와 GetItemData 메서드를 이용하여 처리할 수 있다.


아이템에 상태 정보 넣기.
-----------------------------------------------------------------------------------
LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_STATE;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
item.state = 상태값 조합
item.stateMask = 상태 마스크 플래그 조합
리스트컨트롤.InsertItem(&item);

상태 플래그는 다음과 같다.
LVIS_ACTIVATING
   지원 않함.
LVIS_CUT
   아이콘이 흐리게 보임 (cut & paste 동작시 주로사용)
LVIS_DROPHILITED
   drag&drop시 타겟 리스트 컨트롤일 경우 마우스 오버 상태에 따라 아이템을 하이라이트 시켜줌
LVIS_FOCUSED
   아이템에 포커스 사각형(쩜선 사각형)을 그려줌
LVIS_SELECTED
   아이템이 선택되어진 형태로 표시해줌
LVIS_STATEIMAGEMASK
   아이템의 이미지에 상태 이미지 선택할 수 있도록 함.
LVIS_OVERLAYMASK
   아이템에 오버레이 마스크용 아이콘을 겹쳐서 그려줌

볼드로 표기된 나머지는 상태 마스크와 상태값을 동일하게 넣으면 된다. 내용 자체도 이해하기
쉬우니 간단한 예만 적어본다.

예) 선택되어진 상태로 표시하기.
LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_STATE;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
item.state = LVIS_FOCUSED;
item.stateMask = LVIS_FOCUSED;
리스트컨트롤.InsertItem(&item);

나머지 2개의 상태 마스크는 아래에 별도로 설명을 추가한다.


이미지에 오버레이 마스크 이미지 덧 씌우기.
-----------------------------------------------------------------------------------
LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
item.iImage = 이미지 리스트의 해당 인덱스
item.state = INDEXTOOVERLAYMASK(오버레이 이미지 인덱스);
item.stateMask = LVIS_OVERLAYMASK;
리스트컨트롤.InsertItem(&item);
오버레이 이미지란 기본 이미지(아이콘) 위에, 다른 아이콘을 덧 씌워 그리는 것을 말한다.
탐색기를 살펴보면 단축 아이콘과 같은 경우

위 그림처럼 기본 이미지위에 오버레이 이미지가 그려져 있는 것을 알 수 있다.
이런 식으로 이미지를 두장 겹처서 그릴 때 사용하는 위와 같은 방법을 사용한다.

오버레이에 사용되는 이미지는 기본으로 연결된 이미지 리스트를 사용한다.


상태 이미지를 별도로 추가하기.
-----------------------------------------------------------------------------------
이건 코드를 달기 전에 먼저 간단한 설명을 전하고, 코드를 이용하여 나머지를 설명할 것이다.
리스트 하나 하나의 아이템이 어떤 상태에 따라 아이콘의 모양이 달라진다면 어떻게 구현할까?


(위 그림은 모두 폴더를 나타내는 아이콘이지만 상태에 따라 서로 다른 이미지를 가진다.)

1. 하나의 이미지 리스트에 몽땅 때려 놓고, 그 때 그 때 이미지를 변경한다.
2. LVSIL_STATE 로 이미지 리스트를 별도로 연결하여 놓고, 그 상태의 이미지를 넣는다.

1번 방법을 이용할 경우, 중간에 이미지가 새로 추가되거나 삭제되면 전체 인덱스 순서에
영향을 미치기 때문에 파급효과가 대단히 크다. 물론 많은 코드 수정도 불가피히다.

2번 방법을 이용할 경우, 이미 인덱스를 별도로 밖아 놓은 코드는 변경을 해야하지만 상태에 따른
이미지 변경 코드는 변화가 없다. 또한 기본 이미지리스트의 인덱스에 영향을 받지 않는다.

헤더파일
이미지리스트 작은이미지;
이미지리스트 큰이미지;
이미지리스트 상태이미지;

소스파일
리스트컨트롤.SetImageList(&작은이미지, LVSIL_SMALL);
리스트컨트롤.SetImageList(&큰이미지, LVSIL_NORMAL);
리스트컨트롤.SetImageList(&상태이미지, LVSIL_STATE);
위와 같이 기본 이미지 리스트와는 별도로 상태 이미지를 담은 이미지 리스트를 만들어 연결한다.

LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
item.iImage = 이미지 리스트의 해당 인덱스
item.state = INDEXTOSTATEIMAGEMASK(상태 이미지 인덱스);
item.stateMask = LVIS_STATEIMAGEMASK;
리스트컨트롤.InsertItem(&item);


아이템에 이미지 여러개 넣기??? - 이게 정말 맞는 이해인지 모르겠다 (누가좀.. )
-----------------------------------------------------------------------------------

LVITEM item = {0};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_INDENT;
item.iItem = 아이템 인덱스
item.pszText = 해당 문자열
item.iImage = 이미지 리스트의 해당 인덱스
item.iIndent = 아이템의 이미지 너비의 복수???
리스트컨트롤.InsertItem(&item);

(iIndent 변수는 common control version 4.7 부터 적용되는 기능입니다.)
리스트 컨트롤에서 레포트 스타일일 경우 첫번째 아이템에 여러개의 이미지가 있는 것을 본적이
있는가? (전 본 기억이 없는듯.. 이것도 오늘 공부해서 써본것입니다. -_-)

저 iIndent 값은 기본적으로 0이며, 저기 숫자를 넣으면, 첫번째 아이템이
저 숫자* 아이콘의 너비 만큼 띄워져서 그려진다.
(아래의 그림은 iIdent를 1로 준 상태입니다.)

그림에서 보는 것 처럼 왼쪽에 아이콘의 너비인 16 픽셀만큼 띄워져서 그림이 그려지고. iIndent 값을 높게 주면 그 배수만큼 띄워져서 그려지게 된다.
Custom Draw나 Owner Draw를 이용하면 저기 비워놓은 공간에 먼가 작업을 해줄 수 있겠지만
그냥 쓸 때는 전혀 의미가 없어보인다. 흠..
(누구 자세히 아시는분 계시면 코멘트좀 달아주세요..)

common control version 6.0 부터는 group 이라는 기능이 지원이 되는데.. 아쉽게도 MFC 6.0
에서는 지원이 되지 않습니다. 현재 깔린 툴이 6.0 뿐이라.. 제 컴에 vs2005를 깔게되면 이 내용에
group에 관련된 내용도 추가하도록 하겠습니다. ㅋ~



위의 내용들을 이용하여 제작된 샘플이다.
-----------------------------------------------------------------------------------

이전에 다루었던 장 중에서 하나씩 시작하기의 샘플을 재 사용(-_-;;;) 하였으며 기존과 달라진 점은 공유 폴더나 단축아이콘도 이미지가 정확하게 표현된다는 점이다.

변경된 내용은 다음과 같다.

BOOL CSampleDlg::OnInitDialog()
{
    ... 중간 생략
    int ndx = 0;
    CFileFind finder;
    SHFILEINFO sfi;
    BOOL bWorking = finder.FindFile("C:\\*.*");
    while (bWorking)
    {
        bWorking = finder.FindNextFile();
        SHGetFileInfo(finder.GetFilePath(),
            0,
            &sfi,
            sizeof(SHFILEINFO),
            SHGFI_DISPLAYNAME | SHGFI_TYPENAME| SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_ATTRIBUTES);
        ndx = AddItem2(finder, sfi, ndx);
    }
    // 찾은 파일의 파일속성 정보를 얻기 위하여 SHGFI_ATTRIBUTES 플래그가 추가되었다.

    ... 중간 생략
}

int CSampleDlg::AddItem2(CFileFind& file, SHFILEINFO& sfi, int ndx)
{
    CString szTemp;
    CTime fTime;

    LVITEM item = {0};
   
    // 아이템의 상태 정보를 넣기 위하여 LVIF_STATE 플래그를 추가함.
    item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
    item.iItem = ndx;
    item.iSubItem = 0;
    item.pszText = sfi.szDisplayName;
    item.iImage = sfi.iIcon;
   
    // 단축 아이콘 속성일 경우.. 2번째 이미지를 오버레이 이미지로 사용함.
    if(sfi.dwAttributes & SFGAO_LINK)
    {
        item.state |= INDEXTOOVERLAYMASK(2);
        item.stateMask |= LVIS_OVERLAYMASK;
    }
    // 공뷰 폴더 속성일 경우.. 1번째 이미지를 오버레이 이미지로 사용함.
    else if(sfi.dwAttributes & SFGAO_SHARE)
    {
        item.state |= INDEXTOOVERLAYMASK(1);
        item.stateMask |= LVIS_OVERLAYMASK;
    }

    // 히든 속성일 경우는 별도이 이미지를 사용하지 않고, LVIS_CUT 상태를 이용하여
    // 흐릿하게 보이도록 함.

    if(sfi.dwAttributes & SFGAO_HIDDEN)
        item.state |= LVIS_CUT;

    ndx = m_list.InsertItem(&item);

    ... 중간 생략   
}





Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프
2008. 12. 17. 15:50 Appication/VC++_Control

서브아이템 에디팅 ( MFC ListCtrl 예제 )

아주 오랜만에 컨트롤에 대하여 올려봅니다.
자주 않쓰다보니.. ^^;

리스트컨트롤을 사용하다 보면 서브아이템도 에디팅해야 할때가 있습니다.
요거 하나 쓸라구 클래스 만들기도 귀찬죠.. (이놈에 귀차니즘 -_-)

코드그루에 있는 자료를 좀 수정해서 사용해봅니다.
http://www.codeguru.com/cpp/controls/listview/editingitemsandsubitem/article.php/c1077/

위 자료인데요..
이것도 리스트를 서브클래싱해야되나서 좀 수정해서 걍 그런거 없이 써봅시다.

요건 에디트컨트롤 서브클래싱한 클래스인데요..
않한다면서도 필요하내요 -_-;;;

/////////////////////////////////////////////////
// 에디트컨트롤 헤더

class CLVEdit : public CEdit
{
// Construction
public:
   CLVEdit() { m_nEdit=-1; }
   void BeginEdit(CListCtrl* pList, int ndx);
   void EndEdit(CListCtrl* pList, NMHDR* pNMHDR);

// Attributes
public:
   CRect m_rc;
   BOOL  m_nEdit;

protected:
   //{{AFX_MSG(CLVEdit)
   afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos);
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};

///////////////////////////////////////////////////////////////
// 에디트 컨트롤 소스

BEGIN_MESSAGE_MAP(CLVEdit, CEdit)
   //{{AFX_MSG_MAP(CLVEdit)
   ON_WM_WINDOWPOSCHANGING()
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CLVEdit::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
   lpwndpos->x=m_rc.left;
   lpwndpos->y=m_rc.top;

   if(m_rc.Width() > 0)
      lpwndpos->cx = m_rc.Width();
   if(m_rc.Height() > 0)
      lpwndpos->cy = m_rc.Height();

   CEdit::OnWindowPosChanging(lpwndpos);
}

void CLVEdit::BeginEdit(CListCtrl* pList, int ndx)
{
    CPoint posMouse;
    GetCursorPos(&posMouse);
    pList->ScreenToClient(&posMouse);

    LV_COLUMN lvc;
    lvc.mask=LVCF_WIDTH;

    CRect rcItem;
    pList->GetItemRect(ndx,rcItem,LVIR_LABEL);

    if(rcItem.PtInRect(posMouse))
        m_nEdit=0;

    int nCol=1;
    while(m_nEdit==-1 && pList->GetColumn(nCol,&lvc))
    {
        rcItem.left=rcItem.right;
        rcItem.right+=lvc.cx;

        if(rcItem.PtInRect(posMouse))
            m_nEdit=nCol;

        nCol++;
    }

    if(m_nEdit==-1)
       return;
   
    m_rc = rcItem;
    SetWindowText(pList->GetItemText(ndx, m_nEdit));
}

void CLVEdit::EndEdit(CListCtrl* pList, NMHDR* pNMHDR)
{
     LV_DISPINFO* pDispInfo=(LV_DISPINFO*)pNMHDR;
     CString sEdit=pDispInfo->item.pszText;
 
    if(!sEdit.IsEmpty())
       pList->SetItemText(pDispInfo->item.iItem,m_nEdit,sEdit);
 
    m_nEdit=-1;
    pList->SetItemState(pDispInfo->item.iItem,0,LVNI_FOCUSED|LVNI_SELECTED);
}



위의 헤더와 소스를 걍 Paste 하시거나 파일로 만들어서 첨부하시면 되구요..
다이알로그나 뷰등에서 리스트 컨트롤을 올려다가 사용하실 때..
다음과 같이 처리하시면 됩니다.

헤더에 아래를 하나 선언한다.
CLVEdit m_LVEdit;

소스에서 각 이벤트를 다음과 같이 핸들링한다.
void 마이다이알로그::OnBeginlabeleditList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    LV_DISPINFO* pDispInfo=(LV_DISPINFO*)pNMHDR;
    *pResult=1;

    // 리스트컨트롤에 내장된 에디트컨트롤을 내가 맹글걸로 연결한다.
    HWND hWnd=(HWND)m_list.SendMessage(LVM_GETEDITCONTROL);
    ASSERT(hWnd!=NULL);
    VERIFY(m_LVEdit.SubclassWindow(hWnd));

    // 내부에서 좌표찾아서 에디트를 적당한 곳에 위치시킨다.
    m_LVEdit.BeginEdit(&m_list, pDispInfo->item.iItem);
    *pResult=0;
}

void 마이다이알로그::OnEndlabeleditList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    LV_DISPINFO* pDispInfo=(LV_DISPINFO*)pNMHDR;
 
    // 에디트가 끝나면 그 값을 읽어다가, 선택된 셀에다가 쓴다.
    m_LVEdit.EndEdit(&m_list, pNMHDR);

    // 연결시킨걸 해제한다.
    VERIFY(m_LVEdit.UnsubclassWindow()!=NULL);

    *pResult=0;
}



Posted by 까막백(홈페이지 이동)

posted by 인생의무한루프
2008. 12. 17. 15:47 Appication/VC++_Control

리스트박스 시작하기 ( MFC ListBox 예제 )

잠시 늦어졌던 장을 다시 시작하겠습니다.
회사도 좀 바밨었구, 흠.. 오랜만에 친구 몇명을 만나느라 주말도 좀 시간이 않나고..
이제서야 다시 글을 쓰게 되었습니다.

이번장은 리스트박스에 대하여 간단하게 설명해 봅니다.
리스트 박스는 이전 장에서 다룬 콤보박스에서도 언급되었었지만..

아주 단순하게 아이템을 열거해 놓고, 하나 혹은 여러개를 선택할 수 있는 직관적인
인터페이스를 제공해주는 컨트롤입니다.

컨트롤을 어느정도 다루다 보면 리스트박스(ListBox)보다는 리스트컨트롤(ListCtrl)을 주로
사용하게 되지만 컨트롤 자체의 기능은 나무랄데가 없습니다.


리스트 박스의 일반적인 속성은 스타일 페이지에 다 모여있습니다.
대부분의 속성들은 기존 장들과 겹치는 부분이 있으니,

Selection, Owner draw, Multi-column, Horizontal scroll
이 속성에 대하여 설명드리겠습니다.

1. Selection Property

선택 속성은 다음 그림처럼 4개의 속성으로 분리되어 있습니다


 - None
    이 속성은 아이템을 선택할 수 없고, 어떤 아이템에 포커스만 보여집니다.
    그림처럼 점선 박스만 보여지고, 사실 잘 사용되지 않는 속성입니다.


- Single
   이 속성은 아이템을 단 하나만 선택할 수 있습니다. 화면에 여러가지 아이템중에 단 하나만
   사용자가 선택할 수 있도록제공 함으로써, 중복선택을 인터페이스상에서 차단할 수 있습니다.


- Multiple
   이 속성은 아이템을 여러개 동시에 선택할 수 있습니다. 단 shift 혹은 ctrl 키와 조합하여
   선택하는 것이 아닌 마우스로 클릭하면 선택되고, 다시 클릭하면 해제되는 방법으로
   사용되기 때문에 상당히 불편하죠. 만약 여러개를 선택했다가 해제하려면 일일이 하나씩
   다 클릭해주어 해제시켜야 합니다.


- Extended
   확장 선택 속성으로써, 아이템을 여러개 동시에 선택할 수 있는건 Multiple과 같습니다. 단
   차이점은 Shift키와 Ctrl키를 마우스와 조합하여 선택할 수 있으며, 마우스 왼쪽 버튼만 클릭하면
   아이템을 하나만 선택할 수 있고, Shift키를 조합하여 누르면 이전 선택항목부터 현재까지 사이에
   있는 모든 아이템을 선택할 수 있습니다. 또한 Ctrl키와 조합하여 누르면 이전의 선택 항목은
   보존되고 있는 상태에서 Multiple 속성 처럼 추가적으로 아이템을 하나씩 선택하거나 해제가
   가능해집니다. 가장 일반적으로 사용되는 속성이죠.

2. Owner draw Property

MFC에서 제공해주는 확장 기능으로 다음과 같은 3가지가 있습니다. 몇몇 기본 컨트롤에서
제공해주는 기능으로 컨트롤의 내부를 사용자가 원하는 방식으로 구현할 수 있도록 그 바탕을
제공해 줌으로써 좀더 확장된 사용을 가능하게 해줍니다.

- No
   화장된 사용자 정의 그리기 기능을 사용하지 않고, 제공된 기능만을 사용함을 알립니다.
   일반적으로 모든 컨트롤의 디폴트 속성입니다.

- Fixed
   Owner Draw를 선택하게 되면 기본적으로 제공되는 가상함수
   virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
   위 함수를 사용자가 재 정의하여 (오버라이딩), 주어진 정보를 기준으로 그림을 내맘대로
   그릴 수 있도록 제공해줍니다.
   단, Fixed일 경우는 각각의 아이템마다 높이가 일률적으로 같습니다.

- Variable
   Fixed 처럼 DrawItem을 이용하여 사용자가 직접 그림을 그려주는 부분은 동일하지만,
   virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
   위의 가상함수를 이용하여 아이템의 높이도 개별적으로 다르게 설정할 수 있다는 점이 다릅니다.

3. Multi column Property
리스트 박스에서 제공해주는 속성중에 가장 직관성이 떨어지는 속성으로...
영문을 해석하면 멀티 컬럼을 지원해준다.. 라고 이해할 수 있습니다. 버뜨!!!~~

멀티컬럼이긴 합니다. 단, 사용자가 생각하는 리스트 컨트롤의 멀티 컬럼과는 개념이 좀 많이 다른
환경이라 첨에 좀 당황스럽다는 점만 빼면요.. -_-


아래는 속성을 적용해 놓은 화면입니다. 아이템 크기에 따라 그냥 지맘대로 쪼갭니다. 머 스크롤바도
없고 아무것도 없습니다. 화면에 보이지 않는 아이템을 선택하려면 그냥 마우스로 드래그 해야하고
멀티로 아이템을 선택할 경우는 선택도 지지리 이상해지죠..

저 컬럼의 너비는 SetColumnWidth()라는 함수를 이용하여 조절하실 수 있습니다.
또한 이 속성은 Owner draw를 사용시에 Variable에서는 조합하여 사용하실 수 없습니다.

대충 사용목적을 생각해보면 쫍은 공간에 많은 항목을 넣어놓고, 하나씩 선택할 경우라면
어떻게든 써볼만 하겠다는 생각이 드네요.. ㅎ~

4. Horizonal scroll Property
이 속성을 내용대로 이해하면 수평 스크롤바를 자동으로 지원해주는 것 같지만..
그렇지는 못하다. 수평 스크롤바를 이용할 수 있도록 내부적인 동작만 지원한다는 의미이다.

한 아이템의 글자가 너무 길어 화면폭을 넘어갈 경우, 리스트박스에서는 그냥 잘려 보인다.
이 때 위 속성을 첨부하고 아래와 같은 코드를 이용하여 수평 스크롤바를 생성할 수 있다.

// 주어진 글자가 리스트박스 내에서 길이가 얼마나 되는지 계산한다.
static int GetTextLenEx(CListBox& box, LPCTSTR lpszText)
{
    CSize size;
    CDC *pDC = box.GetDC();
   
    // 현재 리스트박스의 폰트를 얻어와 DC에 적용시킨다.
    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);
   
    // 구한 문자열의 Pixel 단위를 넘긴다.
    return size.cx;
}

// 문자열을 리스트박스에 추가하는 함수.
static void
AddStringEx(CListBox& box, CString str)
{
    // 우선 리스트박스에 문자열을 추가시킨다.
    box.AddString(str);

    // 길이를 계산하여 기존 길이보다 넓으면 새로운 길이를 적용시킨다.
    int iExt = GetTextLenEx(box, str);
    if (iExt > box.GetHorizontalExtent())
        box.SetHorizontalExtent(iExt);
}







Posted by 까막백(홈페이지 이동)


posted by 인생의무한루프
2008. 12. 17. 15:44 Appication/VC++_Control

추가/삽입/삭제/선택 ( MFC ListBox 예제 )

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

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

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]);
}



Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프
2008. 12. 17. 15:43 Appication/VC++_Control

글자색과 배경색 ( MFC ListBox 예제 )

리스트 박스의 글자색과 배경색은 기존에 해온대로 WM_CTLCOLOR 이벤트를
이용하면 아주 쉽게 해결됩니다..



HBRUSH CSssDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
 
    if(nCtlColor == CTLCOLOR_LISTBOX)
    {
        if(pWnd->GetDlgCtrlID() == IDC_LIST1)
        {
            pDC->SetTextColor(RGB(255, 0, 0));
            pDC->SetBkColor(RGB(255,255,0));

            // 노랑색으로 만든 브러쉬. - m_brh.CreateSolidBrush(RGB(255,255,0));
            return m_brh;
        }
    }

    return hbr;
}



지금까지 다룬 방식으로 아주 쉽게 처리가 되었읍니다. -_-
강좌라고 할만한 껀덕지도 없읍니다.

하지만 컨트롤을 오버라이딩해서 별도로 구현하지 않는이상.. 리스트박스는 별로
다룰만한게 없다보니.. 휴~~



Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프
prev 1 2 3 4 5 ··· 9 next