www.gusucode.com > VC++扩展的ColoredListCtrl控件及示例-源码程序 > VC++扩展的ColoredListCtrl控件及示例-源码程序/code/修改后的ColoredListCtrlTest/ColorListCtrl.cpp

    // Author:      SFr frydaysoft@gmx.de
// Download by http://www.NewXing.com
#include "stdafx.h"
#include "ColorListCtrl.h"

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


/////////////////////////////////////////////////////////////////////////////
// CColorListCtrl

CColorListCtrl::CColorListCtrl(int colSize)
{
    m_columnSize=colSize;       // number of columns
    m_fullColumnLines=TRUE;     // paint vert. lines | | |
    m_withSingleRect=FALSE;     // paint single rect for all sub-items
#ifdef _DEBUG
    m_BigFocusRect=TRUE;        // focus-rect with small/big dots
#endif
#ifndef _DEBUG
    m_BigFocusRect=FALSE;       // focus-rect with small/big dots
#endif
    IsCreated=FALSE;
}

//***************************************************************
CColorListCtrl::~CColorListCtrl()
{
}

//***************************************************************
BEGIN_MESSAGE_MAP(CColorListCtrl, CListCtrl)
	//{{AFX_MSG_MAP(CColorListCtrl)
	ON_WM_PAINT()
	ON_WM_DESTROY()
	ON_WM_KILLFOCUS()
	ON_WM_SETFOCUS()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// Behandlungsroutinen f黵 Nachrichten CColorListCtrl 
void CColorListCtrl::OnDestroy() 
{
	DeleteAllItems();	
	CListCtrl::OnDestroy();
}

//***************************************************************
void CColorListCtrl::SetColumnType(BOOL bNew)
{
    m_fullColumnLines=bNew;     // paint no/vert. lines | | |
    if (IsCreated) 
    {
        RedrawWindow();
    }
}
void CColorListCtrl::SetRectType(BOOL bNew)
{
    m_withSingleRect=bNew;     // paint no/single rect for all sub-items
    if (IsCreated)
    {
        RedrawWindow();
    }
}
void CColorListCtrl::SetFocusType(BOOL bNew)
{
    m_BigFocusRect=bNew;       // focus-rect with small/big dots
    if (IsCreated)
    {
        RedrawWindow();
    }
}

//***************************************************************
CMyLParam*	CColorListCtrl::GetMyLParam(int Index)
{
    LVITEM	Item;
	Item.mask		= LVIF_PARAM;
	Item.iItem		= Index;
	Item.iSubItem	= 0;
	CListCtrl::GetItem(&Item);
	return (CMyLParam*)Item.lParam;
}

//***************************************************************
CRect CColorListCtrl::GetFullCellRect(int nItem, BOOL outside)
{
	static CRect rectCell;
    CListCtrl::GetItemRect(nItem, rectCell, LVIR_BOUNDS);
    if (!outside)
    {   //decrease 1 pixel
        rectCell.left++;    rectCell.right--;
        rectCell.top++;     rectCell.bottom--;
    }
	return rectCell;
}

//***************************************************************
CRect CColorListCtrl::GetCellRect(int nItem, int nColumn, BOOL outside)
{
	static CRect rectCell;

	// Get the height
    CListCtrl::GetItemRect(nItem, rectCell, LVIR_BOUNDS);
    LV_COLUMN column;
	column.mask = LVCF_WIDTH;        // Set the mask to only return the width

    for (int x=0; x<nColumn; x++)
    {
        column.iSubItem=1;
        CListCtrl::GetColumn(x, &column); // Get rect-edge (left/top)
        rectCell.left+=column.cx;
    }
    column.iSubItem=1;
    CListCtrl::GetColumn(nColumn, &column); // Get rect-edge (right/bottom)
    rectCell.right = rectCell.left + column.cx;

    if (!outside)
    {   //decrease 1 pixel
        rectCell.left++;    rectCell.right--;
        rectCell.top++;     rectCell.bottom--;
    }
	return rectCell;
}

//***************************************************************
void CColorListCtrl::InvalidateFullItem(int nItem, BOOL bErase)
{
    CRect rcBounds=GetFullCellRect(nItem, TRUE);
	InvalidateRect(rcBounds, bErase);

}

//***************************************************************
// create ListCtrl-head
int CColorListCtrl::InitCtrl(CStringArray *phead, CByteArray *pProcent)
{
    if ( (!phead)||(!pProcent)) return 1;
	LV_COLUMN lvc;
	int cx=0;
    int count = phead->GetSize(); 
    if (count!=m_columnSize) return 2;
    if (pProcent->GetSize() != count) return 3;
    for (int x=0; x<count; x++) cx+=pProcent->GetAt(x);
    if (cx!=100) return 4;

	CRect rect_listbox;

	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	GetWindowRect( rect_listbox );
	cx=int((rect_listbox.right-rect_listbox.left)-20); //some Pixel for Scrollbar

    //set head-columns in ListBox
	lvc.iSubItem = 0;
	lvc.fmt = LVCFMT_LEFT ;		
	
    for (x=0; x<count; x++)
    {
        lvc.cx = int(cx*pProcent->GetAt(x)/100);
	    lvc.pszText = (char*)LPCSTR(phead->GetAt(x));
	    CListCtrl::InsertColumn(x,&lvc);
    }
    return 0;
}


//***************************************************************
// add an item
int CColorListCtrl::AddItem(CStringArray *line, int pos)
{
    int ret_index=LISTCTRL_ERROR;
    if (!line) return ret_index;

	LV_ITEM lvi;
    
	//set List-properties
	lvi.mask = LVIF_TEXT ; 
	lvi.iSubItem = 0;
    lvi.pszText = "";

    int count=GetItemCount();
    int columns=line->GetSize();

    if (m_columnSize!=columns) return ret_index;

    if (DWORD(pos)<=DWORD(count)) count=pos;
	
    lvi.iItem = count;
    //lvi.lParam= count;
	lvi.mask = LVIF_TEXT ; 
	lvi.iSubItem = 0;   //refer to no Item
    // insert an new line
    ret_index=InsertItem(&lvi);
    // set item text for additional columns		
    for (int x=0; x<columns; x++)
    {
        CListCtrl::SetItemText(count,x,(char*)LPCSTR(line->GetAt(x)) );
    }
	lvi.mask = LVIF_STATE;
	lvi.iSubItem = 1;
	lvi.stateMask = 0xFFFFFFFF ; 
	lvi.state = 0;

	if (CListCtrl::SetItem(&lvi)) 
    {
        CMyLParam *p=new CMyLParam(m_columnSize); //init with: DEF_BACKGROUND, def_text

        #ifdef TESTCOLOR
/*            // only for TEST
            if (ret_index<3)
            {
                p->SetBackColor(ITEM_COLOR(ret_index+BLUE),0);
                p->SetTextColor(ITEM_COLOR(ret_index+RED ),0);
            }
            else
            if (ret_index<=6)
            {
                p->SetBackColor(ITEM_COLOR(ret_index+BLUE),1);
                p->SetTextColor(ITEM_COLOR(ret_index+RED ),1);
            }
            else
            {
                p->SetBackColor(ITEM_COLOR((ret_index+BLUE)&0xF),2);
                p->SetTextColor(ITEM_COLOR((ret_index+RED )&0xF),2);
            }
            // end: only for TEST*/
        #endif

        CListCtrl::SetItemData( ret_index, DWORD(p) );
        return ret_index;
    }
    return LISTCTRL_ERROR;
}

//***************************************************************
BOOL CColorListCtrl::DeleteAllItems()
{
	while (CListCtrl::GetItemCount())
        CColorListCtrl::DeleteItem(0);

    return TRUE;
}

//***************************************************************
BOOL CColorListCtrl::DeleteItem(int nItem )
{
    if (CListCtrl::GetItemCount()<=nItem) return FALSE;
    CMyLParam *p=(CMyLParam*)CListCtrl::GetItemData(nItem);
    if (p)
    {
        CListCtrl::SetItemData( nItem, p->GetData() );
        delete p;
        return CListCtrl::DeleteItem( nItem );
    }
    return TRUE;
}


//***************************************************************
DWORD CColorListCtrl::GetItemData( int nItem ) const
{
    CMyLParam *p=(CMyLParam*)CListCtrl::GetItemData(nItem);
    if (p)
    {
        return p->GetData();
        return TRUE;
    }
    return 0;
}

//***************************************************************
BOOL  CColorListCtrl::SetItemData( int nItem, DWORD dwData )
{
    CMyLParam *p=(CMyLParam*)CListCtrl::GetItemData(nItem);
    if (p)
    {
        p->SetData(dwData);
        return TRUE;
    }
    return FALSE;
}

//***************************************************************
BOOL CColorListCtrl::SetItemBackgndColor(COLORREF color, int Index, int iSub)	
{
    CMyLParam *p=GetMyLParam(Index);
    if (!p) return FALSE;
    if ( p->SetBackColor(color, iSub) )
    {
        RedrawItems( Index, Index );
        return TRUE;
    }
    return FALSE;
}

//***************************************************************
BOOL CColorListCtrl::SetItemTextColor(COLORREF color, int Index, int iSub)	
{
    CMyLParam *p=GetMyLParam(Index);
    if (!p) return FALSE;
    if ( p->SetTextColor(color, iSub) )
    {
        RedrawItems( Index, Index );
        return TRUE;
    }
    return FALSE;
}

//***************************************************************
COLORREF CColorListCtrl::GetItemBackgndColor(int Index, int iSub)
{
    CMyLParam *p=GetMyLParam(Index);
    if (!p) return 0;
    return p->GetBackColor(iSub);
}

//***************************************************************
COLORREF CColorListCtrl::GetItemTextColor(int Index, int iSub)
{
    CMyLParam *p=GetMyLParam(Index);
    if (!p) return 0;
    return p->GetTextColor(iSub);
}

//***************************************************************
void CColorListCtrl::OnPaint() 
{
	// First let the control do its default drawing.
	const MSG *msg = GetCurrentMessage();
	DefWindowProc( msg->message, msg->wParam, msg->lParam );

    if (!m_fullColumnLines) return;

	// Draw the lines only for LVS_REPORT mode
	if( (GetStyle() & LVS_TYPEMASK) == LVS_REPORT )
	{
		// Get the number of columns
		CClientDC dc(this );
		CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
		int nColumnCount = pHeader->GetItemCount();

		// The bottom of the header corresponds to the top of the line 
		RECT rect;
		pHeader->GetClientRect( &rect );
		int top = rect.bottom;

		// Now get the client rect so we know the line length and
		// when to stop
		GetClientRect( &rect );

		// The border of the column is offset by the horz scroll
		int borderx = 0 - GetScrollPos( SB_HORZ );

        CPen       *pOldPen;
        CPen        pen;
        CGdiObject *pOldBrush;
        pen.CreatePen( PS_DOT, 0, ::GetSysColor(COLOR_HIGHLIGHTTEXT) );
        pOldPen  =dc.SelectObject(&pen);
        pOldBrush=dc.SelectStockObject(NULL_BRUSH);

		for( int i = 0; i < nColumnCount; i++ )
		{
			// Get the next border
			borderx += GetColumnWidth( i );

			// if next border is outside client area, break out
			if( borderx >= rect.right ) break;

			// Draw the line.
			dc.MoveTo( borderx-1, top);
			dc.LineTo( borderx-1, rect.bottom );
		}
        dc.SelectObject(pOldPen);
        dc.SelectObject(pOldBrush);

	}
	// Do not call CListCtrl::OnPaint() for painting messages
}

//***************************************************************
void CColorListCtrl::RepaintSelectedItems()
{
	// Invalidate focused item so it can repaint 
	int nItem = GetNextItem(-1, LVNI_FOCUSED);

	if(nItem != -1)
	{
        InvalidateFullItem(nItem, FALSE);
	}

	// Invalidate selected items depending on LVS_SHOWSELALWAYS
	if((GetStyle() & LVS_SHOWSELALWAYS))
	{
		for(nItem = GetNextItem(-1, LVNI_SELECTED);
			nItem != -1; nItem = GetNextItem(nItem, LVNI_SELECTED))
		{
            InvalidateFullItem(nItem, FALSE);
		}
	}
	UpdateWindow();
}

//***************************************************************
BOOL CColorListCtrl::SetSel(int pos, BOOL bSelect)
{
    // LVS_ES_FULLROWSELECT only works with newer version of Comctl32
    // This style and some of the other new extended styles 
    // only work with version 4.72 (or higer) of COMCTL32.DLL 

    UINT nState=0;
    if (bSelect) nState=LVIS_SELECTED|LVS_EX_FULLROWSELECT; else nState=0;
    if (SetItemState(pos, nState, LVIS_SELECTED|LVS_EX_FULLROWSELECT))
    {
        if((GetStyle() & LVS_SHOWSELALWAYS))
        {
            InvalidateFullItem(pos, TRUE);
        }
        return TRUE;
    }
    return FALSE;
}
//***************************************************************
void CColorListCtrl::OnKillFocus(CWnd* pNewWnd) 
{
	SendMessage(WM_PAINT);
    CListCtrl::OnKillFocus(pNewWnd);
	// check if we are losing focus
	if(pNewWnd != NULL && pNewWnd->GetParent() == this)
		return;

	// repaint items that should change appearance
	if((GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
		RepaintSelectedItems();
}

//***************************************************************
void CColorListCtrl::OnSetFocus(CWnd* pOldWnd) 
{
	CListCtrl::OnSetFocus(pOldWnd);
	
	// check if we are getting focus
	if(pOldWnd!=NULL && pOldWnd->GetParent()==this)
		return;

	// repaint items that should change appearance
	if((GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
		RepaintSelectedItems();
}

//***************************************************************
void CColorListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    if (!lpDrawItemStruct) return;
    IsCreated=TRUE;
	CDC*		pDC			= CDC::FromHandle(lpDrawItemStruct->hDC);
	CMyLParam*	pMyLParam	= GetMyLParam(lpDrawItemStruct->itemID);
	CRect		rcItem;

    if (!pMyLParam) return;
    int x=0;
    typedef enum {R_NOTHINGS=0, R_FOCUS, R_SELECT, R_NORMAL, R_SEL_NOFOCUS} redrawmode;
    redrawmode redraw=R_NORMAL;

	// Get item image and state info
	LV_ITEM lvi;
	lvi.mask = LVIF_IMAGE | LVIF_STATE;
	lvi.iItem = lpDrawItemStruct->itemID;
	lvi.iSubItem = 0;
	lvi.stateMask = 0xFFFF;		// get all state flags
	GetItem(&lvi);

	BOOL bHighlight =   (   (lvi.state & LVIS_DROPHILITED)
                            ||
				            (
                                (lvi.state & LVIS_SELECTED) 
                                && 
                                (  ( GetFocus() == this )  || ( GetStyle() & LVS_SHOWSELALWAYS ) )
					        )
				        );

    BOOL bLostFocus=(GetFocus()!=this);


    if ( (lpDrawItemStruct->itemAction&ODA_FOCUS)==ODA_FOCUS)
    {   //the control gains or loses input focus
        if (bLostFocus) redraw=R_SEL_NOFOCUS;
        else
        if ((lvi.state&LVIS_FOCUSED)==LVIS_FOCUSED) redraw=R_FOCUS;
        else 
        {
            if (bHighlight) redraw=R_SELECT;
            else redraw=R_NORMAL;
        }
    }
    else
    if ((lpDrawItemStruct->itemAction&ODA_SELECT)==ODA_SELECT)
    {   //the selection status has changed
            if (bHighlight)
            {
                if (bLostFocus) redraw=R_SEL_NOFOCUS;
                 else redraw=R_SELECT;
            }
            else redraw=R_NORMAL;
    }
    else
    {   //redraw the item
        if (bLostFocus)
        {
            if (bHighlight) redraw=R_SEL_NOFOCUS;
             else
              redraw=R_NORMAL;
        }
        else 
        {
            if ((lvi.state&LVIS_FOCUSED)==LVIS_FOCUSED) redraw=R_FOCUS;
            else 
            {
                if (bHighlight) redraw=R_SELECT;
                 else redraw=R_NORMAL;
            }
        }
    }

    CPen       *pOldPen;
    CPen        pen;
    CGdiObject *pOldBrush;

    switch(redraw)
    {

        case R_FOCUS:
            rcItem=GetFullCellRect(lpDrawItemStruct->itemID, TRUE);
            pDC->FillSolidRect(rcItem, ::GetSysColor(COLOR_ACTIVECAPTION));
            pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
            if (m_BigFocusRect)
            {
                pen.CreatePen( PS_DOT, 0, ::GetSysColor(COLOR_HIGHLIGHTTEXT) );
                pOldPen  =pDC->SelectObject(&pen);
                pOldBrush=pDC->SelectStockObject(NULL_BRUSH);
                pDC->Rectangle(rcItem);
                pDC->SelectObject(pOldPen);
                pDC->SelectObject(pOldBrush);
            }
            else pDC->DrawFocusRect(rcItem);
            for (x=0; x<m_columnSize; x++)
            {
                rcItem	= GetCellRect(lpDrawItemStruct->itemID, x, FALSE);
                pDC->DrawText(CListCtrl::GetItemText(lpDrawItemStruct->itemID,x), rcItem, DT_SINGLELINE | DT_LEFT | DT_VCENTER );
            }
            break;
        case R_SELECT:
            rcItem=GetFullCellRect(lpDrawItemStruct->itemID, TRUE);
            pDC->FillSolidRect(rcItem, ::GetSysColor(COLOR_ACTIVECAPTION));
            pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
            for (x=0; x<m_columnSize; x++)
            {
                rcItem	= GetCellRect(lpDrawItemStruct->itemID, x, FALSE);
                pDC->DrawText(CListCtrl::GetItemText(lpDrawItemStruct->itemID,x), rcItem, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
            }
            break;
        case R_SEL_NOFOCUS:
            rcItem=GetFullCellRect(lpDrawItemStruct->itemID, TRUE);
            pDC->FillSolidRect(rcItem, ::GetSysColor(COLOR_INACTIVECAPTION));
            pDC->SetTextColor(pMyLParam->GetTextColor(5));
            pen.CreatePen( PS_DOT, 0, ::GetSysColor(COLOR_INACTIVECAPTION) );
            pOldPen  =pDC->SelectObject(&pen);
            pOldBrush=pDC->SelectStockObject(NULL_BRUSH);
            if (!m_withSingleRect)
                pDC->Rectangle(rcItem);
            for (x=0; x<m_columnSize; x++)
            {
                rcItem	= GetCellRect(lpDrawItemStruct->itemID, x, FALSE);
                pDC->DrawText(CListCtrl::GetItemText(lpDrawItemStruct->itemID,x), rcItem, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
            }
            pDC->SelectObject(pOldPen);
            pDC->SelectObject(pOldBrush);
            break;
        case R_NORMAL:
            for (x=0; x<m_columnSize; x++)
            {
	            rcItem	= GetCellRect(lpDrawItemStruct->itemID, x, TRUE);
                pDC->FillSolidRect(rcItem, pMyLParam->GetBackColor(x));
                pDC->SetTextColor(pMyLParam->GetTextColor(x));
                if (m_withSingleRect)
                {
                    pOldBrush=pDC->SelectStockObject(NULL_BRUSH);
                    pDC->Rectangle(rcItem);
                    pDC->SelectObject(pOldBrush);
                    
                }
                rcItem	= GetCellRect(lpDrawItemStruct->itemID, x, FALSE);
                pDC->DrawText(CListCtrl::GetItemText(lpDrawItemStruct->itemID,x), rcItem, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
            }
            break;
    }

    return;
}

void CColorListCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CListCtrl::OnSize(nType, cx, cy);
    if (IsCreated) 
    {
        RedrawWindow();
    }
}