[MFC 컨트롤] 리스트 컨트롤 색상 다루기

간단하지만 복잡하기도한 리스트 컨트롤 색상 다루기입니다.


칼럼과 행 별로 색상을 컨트롤할 수 있는데요,


일단 코드를 보시면서 말씀드릴게요,


밑의 코드는 제가 프로젝트하던 코드의 일부분입니다 :)


헤더 파일에


 afx_msg void OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult);



이렇게 추가해 주시구요,


메시지맵을 등록해야 겠죠,


BEGIN_MESSAGE_MAP 밑에 이렇게 입력해줍니다.


ON_NOTIFY(NM_CUSTOMDRAW, IDC_RESULT/*컨트롤 리소스 ID*/, OnCustomdrawList)


그리고 사용자 함수를 추가해서 코딩해 줍니다.


void CNetManagerView::OnCustomdrawTcpList(NMHDR* pNMHDR, LRESULT* pResult)
{
 CString strProtocol,strRSTFIN;
 BOOL bEmerFlag = FALSE;
 
 NMLVCUSTOMDRAW* pLVCD = (NMLVCUSTOMDRAW*)pNMHDR;
 
 strProtocol = m_ctrlTCPlist.GetItemText(pLVCD->nmcd.dwItemSpec, 1);
 strRSTFIN = m_ctrlTCPlist.GetItemText(pLVCD->nmcd.dwItemSpec, 9);
 
 if( (strRSTFIN.Find("RST") != -1) || (strRSTFIN.Find("FIN") != -1) )
 {
  bEmerFlag=TRUE;
 }
 
    *pResult = 0;
 
    if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
        *pResult = CDRF_NOTIFYITEMDRAW;
 
    else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
    {
       if( bEmerFlag )        // TCP && 긴급 플래그 일떄
       {
        pLVCD->clrText = RGB(255,102,102);
       }
       pLVCD->clrTextBk = RGB(237,255,255);
  
       if( !bEmerFlag )        // 긴급 플래그가 아닐때
       {
        pLVCD->clrText   = RGB(0, 0, 0);
       }
       *pResult = CDRF_DODEFAULT;
    }
}



프로그램 화면캡쳐의 일부분입니다. 저런식으로 색상을 변경할 수 있습니다.


경우에 따라서 색상을 입히시면 됩니다,


RGB값은 임의로 주시면 되구요, (RGB 색상 표를 참고하세요 )


기본 리스트 컨트롤 배경 색상 및 글자 색상 글자 배경 색상은


API를 제공하고 있습니다.


SetBkColor(), SetTextBkColor() 등을 MSDN을 참고하셔서


사용하시면 됩니다.




[리스트컨트롤-기초05 뽀나스] 리소스 이미지 배경 깔기 & 투명 라벨


OnInitDialog에 추가한 코드는 아래와 같다.

말하자면 전나 쉽다!


    //

    if (!AfxOleInit())

    {

        AfxMessageBox("Unable to initialize OLE.\nTerminating application!");

        return FALSE;

    }


    TCHAR szBuffer[_MAX_PATH];

    VERIFY(::GetModuleFileName(AfxGetInstanceHandle(), szBuffer, _MAX_PATH));

    CString sPath;

    sPath.Format(_T("res://%s/%s/#%d"), szBuffer, _T("JPG"), IDR_JPG1);

    m_list.SetBkImage((LPTSTR)(LPCTSTR)sPath);


    //

    m_list.SetTextBkColor((COLORREF)-1);

    m_list.SetTextColor(GetSysColor(COLOR_3DDKSHADOW));


설명이 필요없다. 걍 보면 안다.




즐감~~!!



listCtrl01.zip




리스트 컨트롤 헤더에 인디케이터 집어넣기

리스트 컨트롤을 사용하다가 보면 컬럼을 클릭했을때 보통 정렬 기능을 구현하게 됩니다.

 정렬기능을 구현해놓고 보면 내림차순인지 오름차순 정렬인지는 사용자가 리스트안에 있는 데이터를 직접 봐야하는데 이것을 시각적으로 표현하기 위해서 보통

 인디케이터를 삽입합니다.  이 기능을 구현하기 위해서 미리 할일은 하나도 없습니다. ^^

 리스트 컨트롤의 어떤 속성도 건드릴 필요없이 바로 몇 줄의 코딩으로 가능합니다.


샘플 코드

다음과 같은 함수를 하나 추가하시고요

void ?????::SetIndicatorOnColumn(int Col)

{

    CHeaderCtrl* pHeader = ????? (리스트컨트롤 이름).GetHeaderCtrl();


    for(int i=0; i<pHeader->GetItemCount(); i++) {

        HDITEM hItem;


        pHeader->GetItem(i, &hItem);


        if(i == Col) {

            hItem.mask = HDI_FORMAT | HDI_BITMAP;

            hItem.fmt |= HDF_BITMAP | HDF_STRING | HDF_BITMAP_ON_RIGHT;

            hItem.hbm = (HBITMAP)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_DOWN), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);

            pHeader->SetItem(i, &hItem);


        }

        else {

            hItem.mask = HDI_FORMAT ;

            hItem.fmt = HDF_STRING;

            hItem.hbm = NULL;

            pHeader->SetItem(i, &hItem);

        }

    }

}


OnColumnClick 함수내에 다음과 같은 코드를 추가합니다.


void ????::OnColumnclickList(NMHDR* pNMHDR, LRESULT* pResult)

{

    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    

    int Col = pNMListView->iSubItem;

    this->SetIndicatorOnColumn(Col);


    (보통 이곳에는 소트에 관련된 함수를 콜하는 코드가 들어가죠)

   ....

   ....


   *pResult = 0;

}


다음과 같은 것으로 작업은 완성 (단 비트맵 리소스로 IDB_UP 혹은 IDB_DOWN의 이름으로 화살표를 그려주어야 합니다. 크기는 5*10 정도가 적당한거 같군요.)


참고로 comctl32.dll 6.0버젼부터는 HDF_SORTDOWN, HDF_SORTUP 이라는 플래그가 추가 되었습니다.




리스트 뷰 간격 조절


p, td, ul, ol, li { font-size:12px; line-height:140%; margin-top:0; margin-bottom:0; } body { font-size:12px; }

CListCtrl 경우는 멤버중 SetIconSpacing() 함수 사용 하면 될것이고.

리스트뷰 일경우에는 ListView_SetIconSpacing 매크로 사용 하시면 됩니다.


단 리스트의 스타일(간단히, 자세히, 아이콘....)에 따라서 지원이 안될수 도 있습니다..






리스트 컨트롤의 컬럼별로 소트하기


//생성자에서 정/역방향 소팅을 위해
//m_bSort=NULL;
//로 셋팅해주시고
//소트하기위한 정보를 가진 클래스를 하나 만듭니다. 뭐 스트럭쳐로 해도 상관없겠져
//스트럭처로 하시면 public:이부분 없어도 되니..
//생성자와 SORT를 위한 참조 변수도 만들구여
class CSortData{
public:

    CSortData(CString str,DWORD dw);
    ~CSortData(){};

    CString m_strText;
    DWORD m_dw;
    
};

CSortData::CSortData(CString str,DWORD dw)
{
    m_strText=str;
    m_dw=dw;
}

//콜백함수를 정의합니다.
//콜백함수에서 데이터를 비교하고 비교한 값을 리턴합니다.
//lParamSort 인자에는 ASCENDING할것인지 DESCENDING할 것인가하는 정보를 받습니다.

static int CALLBACK MyCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    CSortData *pLc1=(CSortData*)lParam1;
    CSortData *pLc2=(CSortData*)lParam2;
    int nReturn=pLc1->m_strText.Compare(pLc2->m_strText);
    if(lParamSort)
        return nReturn;
    else
        return -nReturn;
}

//리스트 컨트롤 아이템 길이를 구해와서 각각의 아이템에 SetItemData를 이용하여 스트럭처정보를
//넣어줍니다.(나중에 소트하기위해)
//그리고 SortItems함수를 호출하는데 이때 위에서 정의한 콜백함수의 포인터를 인자로 넣어주고
//ASCENDING 혹은 DESCENDING할것인지에 대한 boolean값을 같이 보내어 줍니다.
//그럼 OS가 알아서 콜백함수를 계속 호출해서 비교정보를 받아가겠지여..
//소트가 완료된다음에는 
//동적할당한 CSortData 클래스를 메모리에서 삭제해줍니다.
BOOL CTestDlg::SortData(int nCol,BOOL bSort)
{
    LkListCtrl *pLc=(LkListCtrl*)GetDlgItem(IDC_LIST_DATA);
    int totItems = pLc->GetItemCount();
// Callback Item Setting
    for(int i=0; i<totItems; i++) 
    {
        DWORD dw = pLc->GetItemData(i);
        CString txt = pLc->GetItemText(i, nCol);
        pLc->SetItemData( i, (DWORD) new CSortData(txt,dw) );
    }
    if(m_bSort)
        pLc->SortItems(MyCompare, bSort);
    else
    {
        pLc->SortItems(MyCompare, bSort);
    }
    //    m_bSort=!m_bSort;

    for(i=0; i<totItems; i++)
    {
        CSortData* pItem = (CSortData*)pLc->GetItemData(i);
        ASSERT( pItem );
        pLc->SetItemData(i, pItem->m_dw);
        delete pItem;
    }

    return TRUE;
}

//컬럼해드를 클릭했을때 우리가 정의한 SortData라는 함수를 호출하도록 클래스 위저드를 
//이용하여 통지메세지인 LVN_COLUMNCLICK 를 오버라이딩 합니다. 아니면 직접 코딩하셔도 무방하지여.
//BEGIN_MESSAGE_MAP(CTestDlg,CDialog)
//    ON_NOTIFY(LVN_COLUMNCLICK,IDC_LIST_DATA, OnColumnclickListData)
//END_MESSAGE_MAP()
//일케 직접하셔도 되겠져..

//호출시에 몇번째 컬럼인지에 대한 정보와 정방향소트인지, 역방향 소트인지를 결정지어 보내줍니다.
//여기서는 클릭할때마다 바뀌게 해놨습니다.
void CTestDlg:OnColumnclickListData(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    if(!SortData(pNMListView->iSubItem,m_bSort))
        return ;
    m_bSort=!m_bSort;
    *pResult = 0;
}

//자 이렇게 하고 (리스트컨트롤에 자료가 들어있음을 가정하고)
//컴파일해서 컬럼해드를 클릭하여 보면 정/역방향 소팅이 되는것을 눈으로 확인하실수 있으실겁니다.

//약간이라도 도움이 되시길.
//그리고 혹 잘못된 점이 있으면 꼭 알려주세여~
//명절 잘보내시길~~
likehood@hanmail.net
송영배




몇가지 팁

 1. 특정 ROW 포커스 주기
 2. 특정 ROW로 가기
 3. 헤더 컬럼수 얻어오기
 4. 컬럼의 너비를 이쁘게 주기
 5. 한줄 쭉 선택되게 하기, 그리드 라인 주기
 6. 선택한 아이템(ROW)를 지우기
 7. 두 아이템을 스왑 하기
 8.기존에 선택되어있는 것을 해체하기



 1. 특정 ROW 포커스 주기
---------------------------------------------------
 리스트 컨트롤에서 어떤 특정 Row를 선택하게 하고 싶을때
 ( 이때 선택뿐아니라 포커스도 가야 한다.
 포커스가 간다는 의미는 다음에 키다운을 하면 바로 부드럽게
 다음 아이템을 가리키도록 하는 것이다 )

   ListView_SetItemState (pListCtrl->GetSafeHwnd(),         // handle to listview
                          10,         // index to listview item
                          LVIS_FOCUSED | LVIS_SELECTED, // item state
                          0x000F);   //mask

 위와 같이 코딩하면 된다.


 2. 특정 ROW로 가기
---------------------------------------------------
 만일 원하는 Row를 스크롤을 하던 어떻게 하든 화면에 보이게
 하고 싶을때
 
 pListCtrl->EnsureVisible(15, TRUE);

 이렇게 하면 된다.


 3. 헤더 컬럼수 얻어오기
---------------------------------------------------
 헤더 컬럼의 갯수를 알고 싶을때
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();

 또는 pList->GetHeaderCtrl()을 통해서 얻어올수 도 있다.


 4. 컬럼의 너비를 이쁘게 주기
---------------------------------------------------
    공백없이 잘 채워 준다.

부모 다이얼로그의 OnSize에서
void CAttrListDlg::OnSize(UINT nType, int cx, int cy) 
{
    CDialog::OnSize(nType, cx, cy);
    
    // TODO: Add your message handler code here
    if( IsWindow( z_AttrList.m_hWnd ))
    {
        z_AttrList.MoveWindow( 0, 0, cx, cy );
        z_AttrList.SetColumnWidth(1 , LVSCW_AUTOSIZE_USEHEADER);
    }
}


 5. 한줄 쭉 선택되게 하기, 그리드 라인 주기
---------------------------------------------------
 z_AttrList.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT); 


 6. 선택한 아이템(ROW)를 지우기
---------------------------------------------------

CDWordArray m_anDragIndexes;    // 선택한 아이템을 기억하는
 배열

int    CAttrList::fnRemoveItem()
{

    m_anDragIndexes.RemoveAll();
    POSITION pos = GetFirstSelectedItemPosition();
    while (pos)
    {
        m_anDragIndexes.Add(GetNextSelectedItem(pos));
    }

    int nSize = m_anDragIndexes.GetSize();    
    int nRet = -1;
    if( nSize )
        nRet = m_anDragIndexes[0];    

    while( nSize-- )
        DeleteItem( m_anDragIndexes[nSize] );

    m_anDragIndexes.RemoveAll();
    return nRet;
}


 7. 두 아이템을 스왑 하기
---------------------------------------------------
void CAttrList::fnSwapItem( int nItem1, int nItem2 )
{
    int hi = nItem2;
    int lo = nItem1;
    CStringArray rowText;

    LV_ITEM lvitemlo, lvitemhi;
    CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
    int nColCount =pHeaderCtrl->GetItemCount();
            
    rowText.SetSize( nColCount );
    int i;
    for( i=0; i<nColCount; i++)
        rowText[i] = GetItemText(lo, i);
    lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
    lvitemlo.iItem = lo;
    lvitemlo.iSubItem = 0;
    lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED |
        LVIS_FOCUSED | LVIS_SELECTED |
        LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
    
    lvitemhi = lvitemlo;
    lvitemhi.iItem = hi;
    
    GetItem( &lvitemlo );
    GetItem( &lvitemhi );
    
    for( i=0; i<nColCount; i++)
        SetItemText(lo, i, GetItemText(hi, i));
    
    lvitemhi.iItem = lo;
    SetItem( &lvitemhi );
    
    for( i=0; i<nColCount; i++)
        SetItemText(hi, i, rowText[i]);
    
    lvitemlo.iItem = hi;
    SetItem( &lvitemlo );
}

 8.기존에 선택되어있는 것을 해체하기
 -----------------------------------
        int nOldItem = GetSelectionMark();
        if( nOldItem > 0 )
            SetItemState( nOldItem , 0, LVIS_SELECTED);




리스트 컨트롤에 콤보박스 올려놓기


Codeguru 에 있는 내용을 약간 번역 겸 수정했습니다. 

오류 부분도 잡아내서 수정했고요 
그럼 도움이 되셨으면 합니다.  시험용 소소도 같이 올려놓습니다.
즐거운 하루 되세요.....



Step1 : CListCtrl 로부터 파생클래스를 생성한다.
    class  CMyListCtrl  : public CListCtrl   

Step 2: Define HitTestEx()
CMyListCtrl class 에 확장 HitTest 함수를 정의합니다. 이 함수는 마우스 포인터가 위치한 줄과 컬럼의 번
호를 리턴합니다. 

// Returns    - 줄의 인덱스값. 데이타가 없는 줄이면 -1 을 리턴함  .
// point    - point to be tested.
// col        - to hold the column index

int CMyListCtrl::HitTestEx(CPoint &point, int *col) const
{
    int colnum = 0;
    int row = HitTest( point, NULL );   // 기존의 HitTest 함수를 이용하여 줄의 인덱스값을 얻어
옴.

    if( col ) *col = 0;

    // LVS_REPORT 모드 인지 확인함.

    if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
        return row;

    // 보여지는 가장 윗줄과 아랫줄의 인덱스를 얻어옴 

    row = GetTopIndex();
    int bottom = row + GetCountPerPage();

    if( bottom > GetItemCount() )
        bottom = GetItemCount();

    // 컬럼의 갯수를 가져온다. 

    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();


    for( ;row <= bottom;row++)
    {

        // 각 줄의 아이템 영역을 잡아서 Pointer가 그 안에 위치하는지 검사한다.

        CRect rect;
        GetItemRect( row, &rect, LVIR_BOUNDS );

        if( rect.PtInRect(point) )
        {
            // 여기서는 컬럼을 뒤짐
            for( colnum = 0; colnum < nColumnCount; colnum++ )
            {
                int colwidth = GetColumnWidth(colnum);
                if( point.x >= rect.left 
                    && point.x <= (rect.left + colwidth ) )
                {
                    if( col ) *col = colnum;
                    return row;
                }
                rect.left += colwidth;
            }
        }
    }
    return -1;
}

Step 3: Drop Down List 를 생성시키는 함수 추가하기 

// ShowInPlaceList        - Drop Down List 를 생성키키는 함수명 
// Returns            - ComboBox Ctrl에 대한 포인터
// nItem            - 위치한 Cell 의 줄 인덱스
// nCol                - 위치한 Cell 의 컬럼 인덱스 
// lstItems            - A list of strings to populate the control with
// nSel                - drop down list 에서 초기에 설정될 인덱스 

CComboBox* CMyListCtrl::ShowInPlaceList( int nItem, int nCol, 
                    CStringList &lstItems, int nSel )
{
    // The returned pointer should not be saved

    // 선택된 아이템(Cell) 이 Visible 인가를 확인 
    if( !EnsureVisible( nItem, TRUE ) ) return NULL;

    // 컬럼이 유효한가를 확인  
    CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    int nColumnCount = pHeader->GetItemCount();
    if( nCol >= nColumnCount || GetColumnWidth(nCol) < 10 ) 
        return NULL;

    // 모든 컬럼의 길이를 얻어냄 
    int offset = 0;
    for( int i = 0; i < nCol; i++ )
        offset += GetColumnWidth( i );

    CRect rect;
    GetItemRect( nItem, &rect, LVIR_BOUNDS );

    CRect rcClient;
    GetClientRect( &rcClient );
    if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
    {
        CSize size;
        size.cx = offset + rect.left;
        size.cy = 0;
        Scroll( size );
        rect.left -= size.cx;
    }

    rect.left += offset+4;
    rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
    int height = rect.bottom-rect.top;
    rect.bottom += 5*height;
    if( rect.right > rcClient.right) rect.right = rcClient.right;

    DWORD dwStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_HSCROLL
                    |CBS_DROPDOWNLIST|CBS_DISABLENOSCROLL;
    CComboBox *pList = new CInPlaceList(nItem, nCol, &lstItems, nSel);
    pList->Create( dwStyle, rect, this, IDC_IPEDIT );
    pList->SetItemHeight( -1, height);
    pList->SetHorizontalExtent( GetColumnWidth( nCol ));


    return pList;
}

Step 4: Handle the scroll messages
CInPlaceList class 는 drop down list 가 포커스를 잃을때 객체를 지우고(delete) , 파괴(destroy) 하기위
해 설계되었음. 리스트 컨트롤의 스크롤바를 클릭킹 하는 것은 drop down list로 부터 포커스를 가져오지 
못함.그러므로 리스트 컨트롤의 스크롤바를 클릭함으로써 포커스를 가져오는 메시지 핸들러를 작성해야 함.

void CMyListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    if( GetFocus() != this ) SetFocus();
    CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CMyListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    if( GetFocus() != this ) SetFocus();
    CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}

Step 5: 
유저가 drop down list 에서 아이템을 선택하면 LVN_ENDLABELEDIT notification 을 보냄. 따라서 다음의 메
시지 핸들러 추가 

void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
    LV_DISPINFO  *plvDispInfo = (LV_DISPINFO *)pNMHDR;
     LV_ITEM         *plvItem = &plvDispInfo->item;

    if (plvItem->pszText != NULL)
    {
        SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
    }
    *pResult = FALSE;
}

Step 6: 
아래의 코드는 WM_LBUTTONDOWN message에 대한 핸들러임. 이 함수는 이미 다른 곳에 drop down list 가 존
재할때 현재 click 한 곳에 dorp down list를 새로 생성함. 아래 코드는 drop down list 를 생성하기전
에   LVS_EDITLABELS style 을 체크함. 이 부분을 각자에 맞게 수정되어야 함.

void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
    int index;
    CListCtrl::OnLButtonDown(nFlags, point);

    int colnum;
    if( ( index = HitTestEx( point, &colnum )) != -1 )
    {
        UINT flag = LVIS_FOCUSED;
        if( (GetItemState( index, flag ) & flag) == flag )
        {
            
            if( !(GetWindowLong(m_hWnd, GWL_STYLE) & LVS_EDITLABELS) )
            {
                CStringList lstItems;
                lstItems.AddTail( "First Item");
                lstItems.AddTail( "Second Item");
                lstItems.AddTail( "Third 
Item");                             // 이부분을 각자에 맞게 수정하면 됨.
                lstItems.AddTail( "Fourth Item");
                lstItems.AddTail( "Fifth Item");
                lstItems.AddTail( "Sixth Item");
                ShowInPlaceList( index, colnum, lstItems, 2 );
            }
        }
        else
            SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED , 
                    LVIS_SELECTED | LVIS_FOCUSED);
    }
}

Step 7: ComboBox Class 서브 클래싱 하기  
이 클래스에 가장 필요한 부분은 유저가 아이템 선택을 끝냈을 경우  LVN_ENDLABELEDIT message 를 보내는 
기능임. 
에디트가 끝나면 자신을 삭제하기도 해야함. 
에디트 작업은 ,Esc , Enter 키가 눌렸을때 , 유저가 아이템을 선택했을 경우, 입력 포커스를 잃었을때 끝
나야 함.

 // InPlaceList.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CInPlaceList window

class CInPlaceList : public CComboBox
{
// Construction
public:
    CInPlaceList(int iItem, int iSubItem, CStringList *plstItems, int nSel);

// Attributes
public:

// Operations
public:

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CInPlaceList)
    public:
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    //}}AFX_VIRTUAL

// Implementation
public:
    virtual ~CInPlaceList();

    // Generated message map functions
protected:
    //{{AFX_MSG(CInPlaceList)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnKillFocus(CWnd* pNewWnd);
    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnNcDestroy();
    afx_msg void OnCloseup();
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
private:
    int     m_iItem;
    int     m_iSubItem;
    CStringList m_lstItems;
    int     m_nSel;
    BOOL    m_bESC;                // To indicate whether ESC key was pressed
};

/////////////////////////////////////////////////////////////////////////////
// InPlaceList.cpp : implementation file
//

#include "stdafx.h"
#include "InPlaceList.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CInPlaceList

CInPlaceList::CInPlaceList(int iItem, int iSubItem, CStringList *plstItems, int nSel)
{
    m_iItem = iItem;
    m_iSubItem = iSubItem;

    m_lstItems.AddTail( plstItems );
    m_nSel = nSel;
    m_bESC = FALSE;
}

CInPlaceList::~CInPlaceList()
{
}


BEGIN_MESSAGE_MAP(CInPlaceList, CComboBox)
    //{{AFX_MSG_MAP(CInPlaceList)
    ON_WM_CREATE()
    ON_WM_KILLFOCUS()
    ON_WM_CHAR()
    ON_WM_NCDESTROY()
    ON_CONTROL_REFLECT(CBN_CLOSEUP, OnCloseup)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInPlaceList message handlers

int CInPlaceList::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CComboBox::OnCreate(lpCreateStruct) == -1)
        return -1;
    
    // Set the proper font
    CFont* font = GetParent()->GetFont();
    SetFont(font);

    for( POSITION pos = m_lstItems.GetHeadPosition(); pos != NULL; )
    {
        AddString( (LPCTSTR) (m_lstItems.GetNext( pos )) );
    }
    SetCurSel( m_nSel );
    SetFocus();
    return 0;
}

BOOL CInPlaceList::PreTranslateMessage(MSG* pMsg) 
{
    if( pMsg->message == WM_KEYDOWN )
    {
        if(pMsg->wParam == VK_RETURN 
                || pMsg->wParam == VK_ESCAPE
                )
        {
            ::TranslateMessage(pMsg);
            ::DispatchMessage(pMsg);
            return TRUE;                // DO NOT process further
        }
    }
    
    return CComboBox::PreTranslateMessage(pMsg);
}

void CInPlaceList::OnKillFocus(CWnd* pNewWnd) 
{
    CComboBox::OnKillFocus(pNewWnd);
    
    CString str;
    GetWindowText(str);

    // Send Notification to parent of ListView ctrl
    LV_DISPINFO dispinfo;
    dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
    dispinfo.hdr.idFrom = GetDlgCtrlID();
    dispinfo.hdr.code = LVN_ENDLABELEDIT;

    dispinfo.item.mask = LVIF_TEXT;
    dispinfo.item.iItem = m_iItem;
    dispinfo.item.iSubItem = m_iSubItem;
    dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
    dispinfo.item.cchTextMax = str.GetLength();

    GetParent()->GetParent()->SendMessage( WM_NOTIFY, GetParent()->GetDlgCtrlID(), (LPARAM)
&dispinfo );

    PostMessage( WM_CLOSE );
}

void CInPlaceList::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
    if( nChar == VK_ESCAPE || nChar == VK_RETURN)
    {
        if( nChar == VK_ESCAPE )
            m_bESC = TRUE;
        GetParent()->SetFocus();
        return;
    }
    
    CComboBox::OnChar(nChar, nRepCnt, nFlags);
}

void CInPlaceList::OnNcDestroy() 
{
    CComboBox::OnNcDestroy();
    
    delete this;
}

void CInPlaceList::OnCloseup() 
{
    GetParent()->SetFocus();
}




리포트 스타일의 리스트 콘트롤에 행간 높이 조절

 리스트 콘트롤의 행간 높이를 조절하고자 할때,
 원래 윈도우가 날려주는 메세지가 있지만, CListCtrlView 를 이용하는경우 도움이 전혀 안됩니다.
 이경우 마지막 방법은 이미지 리스트를 이용하는 것입니다.

         CImageList m_image;

    ....
         CListCtrl &m_list=GetListCtrl();
    m_image.Create(1,20,ILC_COLORDDB,1,0); 
    list.SetImageList(&m_image,LVSIL_SMALL);
  .......

 을 써서 Y 크기를 조절해서 크기를 바꿀 수 있습니다.
 메세지를 생성하는게 제일 좋은데 어쩔 수 없네요



 그리고

ListView_SetExtendedListViewStyle(list, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_SUBITEMIMAGES);

 을 이용하시면  ROW 전체를 선택하거나, GRID 를 표시해주고,  서브아이템에 이미지 표시하기 등이 가능해
집니다.


BOOL ListCtrl_ModifyExtendedStyle(CListCtrl&   p_rListCtrl,
                                   const DWORD  p_dwStyleEx,
                                   const bool   p_bAdd)
{
    HWND t_hWnd = p_rListCtrl.GetSafeHwnd();
    DWORD t_dwStyleEx = ListView_GetExtendedListViewStyle(t_hWnd);
 
    if(p_bAdd)
    {
        if(0 == (p_dwStyleEx & t_dwStyleEx))
        {
            // add style
            t_dwStyleEx |= p_dwStyleEx;
        }
    }
    else
    {
        if(0 != (p_dwStyleEx & t_dwStyleEx))
        {
            // remove style
            t_dwStyleEx &= ~p_dwStyleEx;
        }
    }
 
    ListView_SetExtendedListViewStyle(t_hWnd, t_dwStyleEx);
 
    return true;
}  


리스트콘트롤에서 원하는 값을 맨위로 오게 스크롤 하기

void CMyListView::SelectListItem(CString text) 

CListCtrl &list = GetListCtrl(); 
LVFINDINFO info; 
int index; 
POINT p; 

info.flags = LVFI_PARTIAL|LVFI_STRING; 
info.psz = text; 

index = list.FindItem(&info) - 1; 
list.SetItemState(index, LVIS_SELECTED | LVIS_FOCUSED, LVIF_STATE); 

list.GetItemPosition(index, &p); 
list.Scroll((CSize)p); 



콘트롤에 멤버 변수를 설정해 놓았으면 맨 첫줄은 필요없구요

아래 list 변수대신 멤버변수를 사용하시면 됨다.

'NativeCode > mfc' 카테고리의 다른 글

리스트 컨트롤 시스템 아이콘 삽입  (0) 2010.03.18
리스트 컨트롤 파일 아이콘 추가하기  (1) 2010.03.18
CTRL 값 얻기  (0) 2010.03.18
배경 그림 넣기  (0) 2010.03.18
부모윈도우 호출  (0) 2010.03.18

+ Recent posts