自定义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;

        for( int 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, 0, 0, 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/


本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2007/08/17/859410.html,如需转载请自行联系原作者
目录
相关文章
|
2月前
设置表格的背景颜色和背景图片
设置表格的背景颜色和背景图片
23 10
|
4月前
|
JavaScript
Elementplus淡入淡出效果,头部顶栏如何设置文字隐藏效果,默认图标如何收缩,icons如何通过类进行替换,侧边栏如何添加阴影,右边如何设置高度,侧边栏如何设置阴影,如何让icon与文字
Elementplus淡入淡出效果,头部顶栏如何设置文字隐藏效果,默认图标如何收缩,icons如何通过类进行替换,侧边栏如何添加阴影,右边如何设置高度,侧边栏如何设置阴影,如何让icon与文字
|
6月前
|
Android开发
ImageView设置tint ,修改图标颜色
ImageView设置tint ,修改图标颜色
82 0
|
11月前
自定义scroll滑块样式
自定义scroll滑块样式
62 0
|
11月前
qrc-标签和按钮、调色板加载图片
qrc-标签和按钮、调色板加载图片
53 0
设置 窗体 静态控件颜色
设置 窗体 静态控件颜色
78 0
tabBar选中的颜色的设置
tabBar选中的颜色的设置
466 0
tabBar选中的颜色的设置
如何让QComboBox控件下拉框自适应文字宽度?
如何让QComboBox控件下拉框自适应文字宽度?
1112 0