自定义ListCtrl中设置背景图片的问题

   自定义的列表控件必须是自绘制的,因此需要在资源编辑器中设置LVS_OWNERDRAWFIXED标志,而且还必须在自定义的控件类中实现DrawItem函数。

200781701.jpg


   代码如下:

class CListCtrlEx : public CListCtrl
{
// Construction
public:
    CListCtrlEx();

public:

    CPalette m_pal;
//调色板
    CBitmap m_bitmap;//背景位图
    int m_cxBitmap, m_cyBitmap;//背景位图高度,宽度信息
    int m_nHighlight;//高亮方式

    BOOL SetBkImage(LPCTSTR lpszResourceName);
//设置背景图片
    BOOL SetBkImage(UINT nIDResource);
    
int GetColumnCount();//获取列数目
    void AdjustColumnWidth();//调整列宽

// Operations
public:

// Overrides
    
// ClassWizard generated virtual function overrides
    
//{{AFX_VIRTUAL(CListCtrlEx)
    
//}}AFX_VIRTUAL

// Implementation
public:
    
virtual ~CListCtrlEx();

    
// Generated message map functions
protected:
    
//{{AFX_MSG(CListCtrlEx)
    afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);//水平滚动
    afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);//垂直滚动
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);//擦除背景
    afx_msg void OnPaletteChanged(CWnd* pFocusWnd);//调色板更改
    afx_msg BOOL OnQueryNewPalette();//查询新调色板
    afx_msg BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
    
//}}AFX_MSG
     virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);//画每一行
    DECLARE_MESSAGE_MAP()
}
;


/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx

CListCtrlEx::CListCtrlEx()
{
   m_nHighlight
=0;
}


CListCtrlEx::
~CListCtrlEx()
{
}



BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
    
//{{AFX_MSG_MAP(CListCtrlEx)
    ON_WM_HSCROLL()
    ON_WM_VSCROLL()
    ON_WM_ERASEBKGND()
    ON_WM_PALETTECHANGED()
    ON_WM_QUERYNEWPALETTE()    
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers
BOOL CListCtrlEx::SetBkImage(UINT nIDResource)
{
    
return SetBkImage((LPCTSTR)nIDResource);
}


BOOL CListCtrlEx::SetBkImage(LPCTSTR lpszResourceName)
{
// If this is not the first call then Delete GDI objects
    if( m_bitmap.m_hObject != NULL )
        m_bitmap.DeleteObject();
    
if( m_pal.m_hObject != NULL )
        m_pal.DeleteObject();


    HBITMAP hBmp 
= (HBITMAP)::LoadImage( AfxGetInstanceHandle(),
            lpszResourceName, IMAGE_BITMAP, 
0,0, LR_CREATEDIBSECTION );

    
if( hBmp == NULL )
        
return FALSE;

    m_bitmap.Attach( hBmp );
    BITMAP bm;
    m_bitmap.GetBitmap( 
&bm );
    m_cxBitmap 
= bm.bmWidth;
    m_cyBitmap 
= bm.bmHeight;


    
// Create a logical palette for the bitmap
    DIBSECTION ds;
    BITMAPINFOHEADER 
&bmInfo = ds.dsBmih;
    m_bitmap.GetObject( 
sizeof(ds), &ds );

    
int nColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1 << bmInfo.biBitCount;

    
// Create a halftone palette if colors > 256. 
    CClientDC dc(NULL);            // Desktop DC
    if( nColors > 256 )
        m_pal.CreateHalftonePalette( 
&dc );
    
else
    
{
        
// Create the palette

        RGBQUAD 
*pRGB = new RGBQUAD[nColors];
        CDC memDC;
        memDC.CreateCompatibleDC(
&dc);

        memDC.SelectObject( 
&m_bitmap );
        ::GetDIBColorTable( memDC, 
0, nColors, pRGB );

        UINT nSize 
= sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
        LOGPALETTE 
*pLP = (LOGPALETTE *new BYTE[nSize];

        pLP
->palVersion = 0x300;
        pLP
->palNumEntries = nColors;

        
forint i=0; i < nColors; i++)
        
{
            pLP
->palPalEntry[i].peRed = pRGB[i].rgbRed;
            pLP
->palPalEntry[i].peGreen = pRGB[i].rgbGreen;
            pLP
->palPalEntry[i].peBlue = pRGB[i].rgbBlue;
            pLP
->palPalEntry[i].peFlags = 0;
        }


        m_pal.CreatePalette( pLP );

        delete[] pLP;
        delete[] pRGB;
    }

    Invalidate();

    
return TRUE;

}


void CListCtrlEx::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    
// TODO: Add your message handler code here and/or call default
    if( m_bitmap.m_hObject != NULL ) 
        InvalidateRect(NULL);    
    
    CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}


void CListCtrlEx::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
    
// TODO: Add your message handler code here and/or call default
    if( m_bitmap.m_hObject != NULL )  
        InvalidateRect(NULL);    
    
    CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}


BOOL CListCtrlEx::OnEraseBkgnd(CDC
* pDC) 
{
    
// TODO: Add your message handler code here and/or call default
    if( m_bitmap.m_hObject != NULL )    
        
return TRUE;
    
    
return CListCtrl::OnEraseBkgnd(pDC);
}


void CListCtrlEx::OnPaletteChanged(CWnd* pFocusWnd) 
{
    CListCtrl::OnPaletteChanged(pFocusWnd);
    
    
// TODO: Add your message handler code here
    if( pFocusWnd == this )    
        
return;

    OnQueryNewPalette();        
}


BOOL CListCtrlEx::OnQueryNewPalette() 
{
    
// TODO: Add your message handler code here and/or call default
    CClientDC dc(this);
    
if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
    
{
        dc.SelectPalette( 
&m_pal, FALSE );
        BOOL result 
= dc.RealizePalette();
        
if( result ) 
            Invalidate();
        
return result;
    }
    
    
    
return CListCtrl::OnQueryNewPalette();
}


void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

    CDC
* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    CRect rcItem(lpDrawItemStruct
->rcItem);
    
int nItem = lpDrawItemStruct->itemID;
    CImageList
* pImageList;

    
// Save dc state
    int nSavedDC = pDC->SaveDC();

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

    
// Should the item be highlighted
    BOOL bHighlight =((lvi.state & LVIS_DROPHILITED)||((lvi.state & LVIS_SELECTED)&&((GetFocus() == this)||
        (GetStyle() 
& LVS_SHOWSELALWAYS))));

    
// Get rectangles for drawing
    CRect rcBounds, rcLabel, rcIcon;
    GetItemRect(nItem, rcBounds, LVIR_BOUNDS);
    GetItemRect(nItem, rcLabel, LVIR_LABEL);
    GetItemRect(nItem, rcIcon, LVIR_ICON);
    CRect rcCol( rcBounds ); 

    CString sLabel 
= GetItemText(nItem, 0 );

    
// Labels are offset by a certain amount  
    
// This offset is related to the width of a space character
    int offset = pDC->GetTextExtent(_T(" "), 1 ).cx*2;

    CRect rcHighlight;
    CRect rcClient;
    
int nExt;
    
switch(m_nHighlight)
    
{
    
case 0
        nExt
=pDC->GetOutputTextExtent(sLabel).cx + offset;
        rcHighlight 
= rcLabel;
//        if( rcLabel.left + nExt 
            
        
if( m_bitmap.m_hObject != NULL )
        
{
               CDC tempDC;
            tempDC.CreateCompatibleDC(pDC);
            tempDC.SelectObject( 
&m_bitmap );

            GetClientRect(
&rcClient);

            CRgn rgnBitmap;
            CRect rcTmpBmp( rcItem );
        
            rcTmpBmp.right 
= rcClient.right;

            
// We also need to check whether it is the last item
            
// The update region has to be extended to the bottom if it is
            if( nItem == GetItemCount() - 1 )    
                rcTmpBmp.bottom 
= rcClient.bottom;

            rgnBitmap.CreateRectRgnIndirect(
&rcTmpBmp);
            pDC
->SelectClipRgn(&rgnBitmap);
            rgnBitmap.DeleteObject();
        
            
if( pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
            
{
                pDC
->SelectPalette( &m_pal, FALSE );
                pDC
->RealizePalette();
            }


            CRect rcFirstItem;
            GetItemRect(
0, rcFirstItem, LVIR_BOUNDS);

            
for (int i = rcFirstItem.left; i < rcTmpBmp.right; i += m_cxBitmap)
                
for (int j = rcFirstItem.top; j < rcTmpBmp.bottom; j += m_cyBitmap)
                    pDC
->BitBlt(i, j, m_cxBitmap, m_cyBitmap, &tempDC, 00, SRCCOPY);

        }

    }

    
// Draw the background color
    if( bHighlight )
    
{
        pDC
->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
        pDC
->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));

        pDC
->FillRect(rcHighlight, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
    }

    
else if( m_bitmap.m_hObject == NULL )
        pDC
->FillRect(rcHighlight, &CBrush(::GetSysColor(COLOR_WINDOW)));

    

    
// Set clip region
    rcCol.right = rcCol.left + GetColumnWidth(0);
    CRgn rgn;
    rgn.CreateRectRgnIndirect(
&rcCol);
    pDC
->SelectClipRgn(&rgn);
    rgn.DeleteObject();

    
// Draw state icon
    if (lvi.state & LVIS_STATEIMAGEMASK)
    
{
        
int nImage = ((lvi.state & LVIS_STATEIMAGEMASK)>>12- 1;
        pImageList 
= GetImageList(LVSIL_STATE);
        
if (pImageList)
        
{
            pImageList
->Draw(pDC, nImage,
                CPoint(rcCol.left, rcCol.top), ILD_TRANSPARENT);
        }

    }

    
    
// Draw normal and overlay icon
    pImageList = GetImageList(LVSIL_SMALL);
    
if (pImageList)
    
{
        UINT nOvlImageMask
=lvi.state & LVIS_OVERLAYMASK;
        pImageList
->Draw(pDC, lvi.iImage, 
            CPoint(rcIcon.left, rcIcon.top),
            (bHighlight
?ILD_BLEND50:0| ILD_TRANSPARENT | nOvlImageMask );
    }


    
    
    
// Draw item label - Column 0
    rcLabel.left += offset/2;
    rcLabel.right 
-= offset;

    pDC
->DrawText(sLabel,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP 
                
| DT_VCENTER | DT_END_ELLIPSIS);


    
// Draw labels for remaining columns
    LV_COLUMN lvc;
    lvc.mask 
= LVCF_FMT | LVCF_WIDTH;

    
if( m_nHighlight == 0 )        // Highlight only first column
    {
        pDC
->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
        pDC
->SetBkColor(::GetSysColor(COLOR_WINDOW));
    }

    
    rcBounds.right 
= rcHighlight.right > rcBounds.right ? rcHighlight.right :
                            rcBounds.right;
    rgn.CreateRectRgnIndirect(
&rcBounds);
    pDC
->SelectClipRgn(&rgn);
                   
    
for(int nColumn = 1; GetColumn(nColumn, &lvc); nColumn++)
    
{
        rcCol.left 
= rcCol.right;
        rcCol.right 
+= lvc.cx;

        
// Draw the background if needed&& m_nHighlight == HIGHLIGHT_NORMAL
        if( m_bitmap.m_hObject == NULL  )
            pDC
->FillRect(rcCol, &CBrush(::GetSysColor(COLOR_WINDOW)));

        sLabel 
= GetItemText(nItem, nColumn);
        
if (sLabel.GetLength() == 0)
            
continue;


        
// Get the text justification
        UINT nJustify = DT_LEFT;
        
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
        
{
        
case LVCFMT_RIGHT:
            nJustify 
= DT_RIGHT;
            
break;
        
case LVCFMT_CENTER:
            nJustify 
= DT_CENTER;
            
break;
        
default:
            
break;
        }


        rcLabel 
= rcCol;
        rcLabel.left 
+= offset;
        rcLabel.right 
-= offset;

        pDC
->DrawText(sLabel, -1, rcLabel, nJustify | DT_SINGLELINE 
                
| DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS);
    }


    
// Draw focus rectangle if item has focus
    if (lvi.state & LVIS_FOCUSED && (GetFocus() == this))
        pDC
->DrawFocusRect(rcHighlight);

    
    
// Restore dc
    pDC->RestoreDC( nSavedDC );

}


void CListCtrlEx::AdjustColumnWidth()
{
    SetRedraw(FALSE);
    
int nColumnCount = GetColumnCount();

    
for(int i = 0; i < nColumnCount; i++)
    
{
        SetColumnWidth(i, LVSCW_AUTOSIZE);
        
int nColumnWidth = GetColumnWidth(i);
        SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER);
        
int nHeaderWidth = GetColumnWidth(i);

        SetColumnWidth(i, max(nColumnWidth, nHeaderWidth));
    }

    SetRedraw(TRUE);
}


int CListCtrlEx::GetColumnCount()
{
    CHeaderCtrl
* pHeaderCtrl = GetHeaderCtrl();
    
return(pHeaderCtrl->GetItemCount());
}


BOOL CListCtrlEx::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT
* pResult)
{
    HD_NOTIFY    
*pHDN = (HD_NOTIFY*)lParam;

    
// This code is for using bitmap in the background
    
// Invalidate the right side of the control when a column is resized
    if(pHDN->hdr.code == HDN_ITEMCHANGINGW || pHDN->hdr.code == HDN_ITEMCHANGINGA)
    
{
        
if( m_bitmap.m_hObject != NULL )
        
{
            CRect rcClient;
            GetClientRect( 
&rcClient );
            DWORD dwPos 
= GetMessagePos();
            CPoint pt( LOWORD(dwPos), HIWORD(dwPos) );
            ScreenToClient( 
&pt );
            rcClient.left 
= pt.x;
            InvalidateRect( 
&rcClient );
        }

    }

    
return CListCtrl::OnNotify(wParam, lParam, pResult);
}


BOOL CCdDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    
// Add "About" menu item to system menu.

    
// IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0== IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX 
< 0xF000);

    CMenu
* pSysMenu = GetSystemMenu(FALSE);
    
if (pSysMenu != NULL)
    
{
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        
if (!strAboutMenu.IsEmpty())
        
{
            pSysMenu
->AppendMenu(MF_SEPARATOR);
            pSysMenu
->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }

    }


    
// Set the icon for this dialog.  The framework does this automatically
    
//  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    m_list.InsertColumn(
0,_T("用户编号"));
    m_list.InsertColumn(
1,_T("  用户名称  "));
    m_list.InsertColumn(
2, _T("年龄"));
    m_list.InsertColumn(
3, _T("性别"));
    m_list.InsertColumn(
4,_T(" 用户住址 "));
    
char ch[5];

    
for(int j=1;j<=200;j++)
    
{
        m_list.InsertItem(j,itoa(j,ch,
10));
    }


    
for(int i = 0;i<200;i++)
    
{
        
        m_list.SetItemText(i,
1,strcat(itoa(i+1,ch,10),"号用户"));
        m_list.SetItemText(i,
2,itoa((i+100)%100,ch,10));
        
if(i%2==0)
        
{
            m_list.SetItemText(i,
3,"");
        }

        
else
        
{
            m_list.SetItemText(i,
3,"");
        }

        m_list.SetItemText(i,
4,strcat(itoa(i+1,ch,10),"号大街"));
    }


    
      
      ListView_SetExtendedListViewStyle(m_list.m_hWnd,LVS_EX_FULLROWSELECT
|LVS_EX_FLATSB|LVS_EX_HEADERDRAGDROP );    
    m_list.SetBkImage(IDB_Bless);
    m_list.AdjustColumnWidth();
    
return TRUE;  // return TRUE  unless you set the focus to a control
}

效果如图所示:
200781702.jpg
   
但是这里还有一个问题,就是当下拉滚动条的时候,如何让背景图片不动,而只是数据行变化,这是接下来要做的工作。

 

参考资料:

http://www.codeguru.com/Cpp/controls/listview/backgroundcolorandimage/article.php/c983/

posted on 2007-08-17 11:10  Phinecos(洞庭散人)  阅读(6276)  评论(11编辑  收藏  举报

导航