list control自绘

自行绘制 ClistCtrl 的列表项,可以利用列表框的 NM_CUSTOMDRAW 消息,该消息由控件向它的父窗口发送,告诉父窗口它的绘图操作。
    如果绘图操作不需要父窗口参与,可以使用该控件的 ON_NOTIFY_REFLECT 宏处理它的 NM_CUSTOMDRAW 消息。

    它的处理函数的参数中包含 NMHDR,在 CUSTOMDRAW 的通知下 NMHDR 可以被转换成为 NMLVCUSTOMDRAW 结构,该结构包含了列表控件中需要自绘区域的全部信息:

typedef struct tagNMLVCUSTOMDRAW
{
NMCUSTOMDRAW   nmcd;                // 包含客户自绘控件信息的结构
COLORREF             clrText;              // 列表视图显示文字的颜色
COLORREF             clrTextBk;          // 列表视图显示文字的背景色
} NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW;

typedef struct tagNMLVCUSTOMDRAW
{
NMCUSTOMDRAW nmcd;
COLORREF clrText;                     //列表视图显示文字的颜色
COLORREF clrTextBk;                 //列表视图显示文字的背景色
#if (_WIN32_IE >= 0x0400)
int iSubItem;                             //子项编号
#endif
#if (_WIN32_WINNT >= 0x501)
DWORD dwItemType;               //

    // Item custom draw
COLORREF clrFace;                   //
int iIconEffect;
int iIconPhase;
int iPartId;
int iStateId;

    // Group Custom Draw
RECT rcText;
UINT uAlign;      // Alignment. Use LVGA_HEADER_CENTER, LVGA_HEADER_RIGHT, LVGA_HEADER_LEFT
#endif
} NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW;

NMCUSTOMDRAW 结构定义如下:

typedef struct tagNMCUSTOMDRAWINFO
{
NMHDR     hdr;                     // 含有通知信息的 NMHDR 结构
DWORD   dwDrawStage;       // 目前绘制的步骤
HDC         hdc;                     // 设备上下文句柄
RECT        rc;                       // 绘制的区域
DWORD    dwItemSpec;        // 绘制项的说明
UINT        uItemState;          // 当前项的状态
LPARAM   lItemlParam           // 应用程序定义的数据
} NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;

    NMLVCUSTOMDRAW.nmcd.dwDrawStage 字段,它主要包含以下几个枚举值:

CDDS_PREPAINT:表示在绘画前阶段。
CDDS_ITEMPREPAINT:表示在列表项的绘画前阶段。
CDDS_SUBITEM:表示绘制子项。
CDDS_ITEM:表示要绘制项的信息已经可用。
    自绘时,可以通过处理以上几个绘画阶段的通知来实现。

例子详细步骤:

利用 MFC AppWizard( exe ) 创建一个新工程 TestCListCtrl。在向导的第 ( 1 ) 步选择单文档模式,而后使用默认值来创建,最后获得一个支持文档视图的应用程序。
在 ClassView 中添加新的类 CCoolListCtrl,类型为 MFC Class,基类为CListCtrl。获得两个新文件 CCoolListCtrl.cpp 和 CCoolListCtrl.h。
在类 CCoolListCtrl 中添加成员变量 m_imagelist 用于存储图像列表。
添加 NM_CUSTOMDRAW 消息的处理函数 OnCustomDraw。
CCoolListCtrl.h 文件中:
afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);//消息函数声明

CCoolListCtrl.cpp 文件中:
// 消息映射宏中添加:ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)

BEGIN_MESSAGE_MAP(CCoolListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CCoolListCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

// 消息处理函数实现:

/
// CCoolListCtrl message handlers

void CCoolListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast <NMLVCUSTOMDRAW*> ( pNMHDR );

    *pResult = 0;
// Request item-specific notifications if this is the
// beginning of the paint cycle.

    if ( CDDS_PREPAINT  == pLVCD-> nmcd.dwDrawStage )
{
*pResult = CDRF_NOTIFYITEMDRAW;
}
else if ( CDDS_ITEMPREPAINT == pLVCD-> nmcd.dwDrawStage )
{
// This is the beginning of an item 's paint cycle.
LVITEM rItem;
int  nItem = static_cast <int> ( pLVCD-> nmcd.dwItemSpec );
CDC* pDC = CDC::FromHandle ( pLVCD-> nmcd.hdc );
COLORREF crBkgnd;
BOOL bListHasFocus;
CRect  rcItem;
CRect  rcText;
CString  sText;
UINT uFormat;

        bListHasFocus = ( this->GetSafeHwnd() == ::GetFocus() );

        // Get the image index and selected/focused state of the
// item being drawn.
ZeroMemory ( &rItem, sizeof(LVITEM) );
rItem.mask  = LVIF_IMAGE | LVIF_STATE;
rItem.iItem = nItem;
rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
this->GetItem ( &rItem );

        // Get the rect that holds the item 's icon.
this->GetItemRect ( nItem, &rcItem, LVIR_ICON );

        // Draw the icon.
uFormat = ILD_TRANSPARENT;

        if ( ( rItem.state & LVIS_SELECTED ) && bListHasFocus )
uFormat |= ILD_FOCUS;

        m_imagelist.Draw ( pDC, rItem.iImage, rcItem.TopLeft(), uFormat );

        // Get the rect that bounds the text label.
this->GetItemRect ( nItem, rcItem, LVIR_LABEL ); //把这行去掉就没有文字.

        // Draw the background of the list item. Colors are selected
// according to the item 's state.

        if ( rItem.state & LVIS_SELECTED )
{
if ( bListHasFocus )
{
crBkgnd = GetSysColor ( COLOR_HIGHLIGHT );
pDC-> SetTextColor ( GetSysColor ( COLOR_HIGHLIGHTTEXT ));
}
else
{
crBkgnd = GetSysColor ( COLOR_BTNFACE );
pDC-> SetTextColor ( GetSysColor ( COLOR_BTNTEXT ));
}
}
else
{
crBkgnd = GetSysColor ( COLOR_WINDOW );
pDC-> SetTextColor ( GetSysColor ( COLOR_BTNTEXT ));
}

        // Draw the background & prep the DC for the text drawing. Note
// that the entire item RECT is filled in, so this emulates the full-
// row selection style of normal lists.
pDC-> FillSolidRect ( rcItem, crBkgnd );
pDC-> SetBkMode ( TRANSPARENT );

        // Tweak the rect a bit for nicer-looking text alignment.
rcText = rcItem;
// Draw the text.
sText = this->GetItemText ( nItem, 0 );

        pDC-> DrawText ( sText, CRect::CRect(rcText.left+3,rcText.top,rcText.right,rcText.bottom+60), DT_VCENTER );

        // Draw a focus rect around the item if necessary.
if ( bListHasFocus && ( rItem.state & LVIS_FOCUSED ))
{
pDC-> DrawFocusRect ( rcItem );
}

        *pResult = CDRF_SKIPDEFAULT; // We 've painted everything.
}
}

在视图类 CTestCListCtrlView 中添加成员变量 m_ListCtrl,类型为 CCoolListCtrl。
定义 WM_CREATE 消息的处理函数 CTestCListCtrlView ::Create,用于创建 CCoolListCtrl 控件,代码如下:
//创建列表控件:自绘样式、没有列头部、处理通知
m_ListCtrl.Create(LVS_OWNERDRAWFIXED | LVS_NOCOLUMNHEADER | LBS_NOTIFY, CRect(0,0,400,200), this, IDC_LISTCTRL );

// 可以使用 m_ListCtrl.SetExtendedStyle 设置扩展样式

// 用自己编写的函数设置图像列表

m_ListCtrl.SetImagelist(IDB_IMAGE);  

// 用自己编写的函数设置列表项的行高,方法见文章《CListCtrl行高的修改》
m_ListCtrl.SetItemHeight(36);

// 插入项

m_ListCtrl.InsertItem(0, "Monroeville", 0); 
m_ListCtrl.InsertItem(1, "Hartford", 1); 
m_ListCtrl.InsertItem(2, "Redmond", 2);

设置图像列表的函数:首先将作为图像列表的bmp文件导入到工程资源中,uBitmap是其资源ID
BOOL CCoolListCtrl::SetImagelist(UINT uBitmap)
{
m_imagelist.DeleteImageList();
m_imagelist.Create(32, 32, ILC_COLOR24|ILC_MASK, 8, 1);
CBitmap bitmap;
bitmap.LoadBitmap(uBitmap);
m_imagelist.Add(&bitmap, RGB(255,0,255));

    return TRUE;
}

    采用添加 NM_CUSTOMDRAW 消息的处理函数 OnCustomDraw 的方式来自绘,遇到了一点问题:

    创建 ClistCtrl 时使用 LVS_OWNERDRAWFIXED 样式的话,在OnCustomDraw 函数中:

switch(pLVCD-> nmcd.dwDrawStage) //绘画阶段
{

        case CDDS_PREPAINT:        //在绘画前阶段
*pResult = CDRF_NOTIFYSUBITEMDRAW;          //返回列表项绘画通知
break;
case CDDS_ITEMPREPAINT:  //在列表项的绘画前阶段
*pResult = CDRF_NOTIFYSUBITEMDRAW;          //返回子列表项绘画通知
break;
case CDDS_ITEMPREPAINT|CDDS_SUBITEM:          //绘画列表项或子项
{
int iCol = lplvcd->iSubItem;
int iRow = lplvcd->nmcd.dwItemSpec;
CString sItem = GetItemText(iRow, iCol);
CRect rc;
GetCellRect(iRow, iCol, LVIR_BOUNDS, rc);
// get the device context.
CDC *pDC= CDC::FromHandle(lplvcd->nmcd.hdc);
// paint the text centered.
pDC->DrawText(sItem , rc, DT_CENTER);
*pResult= CDRF_SKIPDEFAULT;
break;
}
default:
*pResult = CDRF_DODEFAULT;// 控件完成自绘,不再发送 NM_CUSTOMDRAW 消息

       return ;

}

*pResult = CDRF_NOTIFYSUBITEMDRAW; 返回子列表项绘画通知时,弹出了错误:

debug assertion failed

program .....exe
file :winctrl2.cpp
line :547

而且似乎进不了case CDDS_ITEMPREPAINT|CDDS_SUBITEM,不知何故。

原来 CListCtrl 的派生类,使用 LVS_OWNERDRAWFIXED 的样式的话,必须重载 DrawItem 函数来绘制各项,否则就取消 LVS_OWNERDRAWFIXED 的样式。

但取消 LVS_OWNERDRAWFIXED 的样式的话,就无法自行设置列表项的行高了。

所以将 OnCustomDraw 换成重载 DrawItem 的方式。

例如:

void CCoolListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDIS) 
{
LVITEM   rItem;
int      nItem = lpDIS->itemID;
CDC*     pDC = CDC::FromHandle (lpDIS->hDC);
//    COLORREF crBkgnd;
BOOL     bListHasFocus;
CRect    rcItem;
CRect    rcCell;
CRect    rcText;
CString  sText;
UINT     uFormat;

    LV_COLUMN lvc;
::ZeroMemory(&lvc, sizeof(lvc));
lvc.mask = LVCF_WIDTH | LVCF_FMT; 
int intColumnCount; 
for (intColumnCount=0; GetColumn(intColumnCount, &lvc); intColumnCount++)
{
bListHasFocus = ( GetSafeHwnd() == ::GetFocus() );

        // Get the image index and selected/focused state of the
// item being drawn.
ZeroMemory ( &rItem, sizeof(LVITEM) );
rItem.iSubItem = intColumnCount;
rItem.mask  = LVIF_IMAGE | LVIF_STATE;
rItem.iItem = nItem;
rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
VERIFY(GetItem(&rItem));

        GetSubItemRect(lpDIS->itemID, intColumnCount,LVIR_BOUNDS, rcCell);    
if (intColumnCount == 0)
{
rcItem = rcCell;
rcCell.right = GetColumnWidth(0);

// Draw the icon.
uFormat = ILD_TRANSPARENT;
if ( ( rItem.state & LVIS_SELECTED ) && bListHasFocus )
uFormat |= ILD_FOCUS;

        // 居中绘画图标
CPoint picPt;
picPt.x = rcCell.left+(rcCell.Width()-32)/2;
picPt.y = rcCell.top+(rcCell.Height()-32)/2;
m_imagelist.Draw ( pDC, rItem.iImage, picPt, uFormat );

         // Tweak the rect a bit for nicer-looking text alignment.
rcText = rcItem;
// Draw the text.
sText = this->GetItemText ( nItem, 0 );
pDC-> DrawText ( sText, CRect::CRect(rcText.left+3,rcText.top,rcText.right,rcText.bottom+60), DT_VCENTER );

    }
return ;
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值