ListCtrl 颜色控制

来源:互联网 发布:nodejs和java哪个好 编辑:程序博客网 时间:2024/05/04 10:34

 http://tech.cixiong.com/t/200501/13/0584162.html
一个有点难的问题,像各位请教!!!
2005-01-13 09:17:57发贴人: microibm
我建了个CListView的对象,这个视图中的ListCtrl (Report型)中用来显示数据,所显示的数据是实时变化的,并且,各个显示数值的SubItem要求有背景色,且背景色并不总占满整个SubItem的区域, 而是根据数值的大小,背景色的长度会变化,而且长度在不同的范围内,颜色也不一样.

举例说明:

以下为CListView中的ListCtrl
------------------------------------------
|    ParaHeader   |      ValueHeader     |
------------------------------------------
|    Para1        |      Value1          |
------------------------------------------
|    Para2        |      Value2          |
------------------------------------------

如图所示,Value1, Value2为两个不断变化的值, 要求这两个值所在的SubItem有背景色,且背景色根据Value1,Value2的大小变化,相应变长或缩短(从左到右)

请问该如何实现啊?
2005-01-13 11:16:35回复人: dandycheung
接收 NM_CUSTOMDRAW 消息,自绘制
2005-01-13 11:22:00回复人: sjhunter
贴段代码给你,但是无论如何你要在DC里画些东西
2005-01-13 11:24:08回复人: sjhunter
void CEditorList::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
// This function is called by the control in different
// stages during the control drawing process.
NMLVCUSTOMDRAW *pCD = (NMLVCUSTOMDRAW*)pNMHDR;
// By default set the return value to do the default behavior.
*pResult = 0;

switch( pCD->nmcd.dwDrawStage )
{
case CDDS_ITEMPREPAINT: // Stage three (called for each subitem of the focused item)
{
*pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NOTIFYPOSTPAINT | CDRF_NEWFONT;
}
break;
//Here we draw the expanded and collapsed icons and the column
case  CDDS_POSTPAINT :
{
*pResult = CDRF_DODEFAULT;
}
break;
case  CDDS_PREPAINT:  // First stage (for the whole control)
{
// Tell the control we want to receive drawing messages 
// for drawing items.
*pResult = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT;
}
break;
case CDDS_ITEMPREPAINT | CDDS_SUBITEM: // Stage three (called for each subitem of the focused item)
{
// We don't want to draw anything here, but we need to respond
// of DODEFAULT will be the next stage.
// Tell the control we want to handle drawing after the subitem
// is drawn.
*pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NOTIFYPOSTPAINT;
}
break;
case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: // Stage four (called for each subitem of the focused item)
{
// We do the drawing here (well maybe).
// This is actually after the control has done its drawing
// on the subitem.  Since drawing a cell is near instantaneous
// the user won't notice.
// If this subitem is the subitem with the current focus,
// draw it.  Otherwise let the control draw it. 
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
ASSERT(NULL != pHeader);
// We have to take into account the possibility that the
// columns may be reordered.
int nItem = pCD->nmcd.dwItemSpec;
int nSubItem = Header_OrderToIndex(pHeader->m_hWnd,  pCD->iSubItem);

// Get drawing dc
CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc);
if (nSubItem == 0)
{
CRect rect;
GetSubItemRectEx(nItem, 0, rect);
pDC->DrawFrameControl(rect, DFC_BUTTON, DFCS_BUTTONPUSH);
CImageList * pImage = GetImageList(LVSIL_SMALL);
POINT pt;
pt.x = rect.left; pt.y = rect.top;
int nState = GetItemState(nItem, 0xFFFF);
pImage->Draw(pDC, ((nState&LVIS_SELECTED)!=0), pt, ILD_TRANSPARENT);
*pResult = CDRF_SKIPDEFAULT;
return;
}
else if (m_nCurSubItem == nSubItem
&& (pCD->nmcd.uItemState & CDIS_FOCUS)
&& nSubItem >= IDX_FM_FAMILY)
{
/*
int nState = GetItemState(nItem, 0xFFFF);
SetItemState(nItem, nState&(~(LVIS_SELECTED|LVIS_FOCUSED)), 0xFFFF);
CRect rect;
GetItemRect(nItem, rect, LVIR_BOUNDS);
InvalidateRect(rect, TRUE);
*/
DrawFocusSubItem(pDC, nItem, nSubItem);
*pResult = CDRF_SKIPDEFAULT;
return;
}
else
{
*pResult = CDRF_DODEFAULT;
return;
}
}
break;
default: // Stage two handled here. (called for each item)
{
*pResult = CDRF_NOTIFYSUBITEMDRAW;
break;
}
}
2005-01-13 11:27:07回复人: sjhunter
这是我以前项目里的代码,这个ListCtrl功能比你的要求复杂多了,我处理了case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
觉得足够解决你的问题了。
这样映射消息
CPP
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
H
afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
别放在Class Wizard的//}}AFX_MSG_MAP里面,否则VC会冲掉它
2005-01-13 11:56:02回复人: microibm
dandycheung(珠穆朗玛) ,sjhunter:
  谢谢两位!
  不过能不能说得在具体点.

  NM_CUSTOMDRAW 是个自定义的消息吧? 在Class Wizard中好象没看到.

sjhunter:
  我的情况可能和你有一点点不同吧,我用的是CListView中的ListCtrl.
   你的代码中能实现SubItem文字的背景色占满一半SubItem的区域那样的情况吗?

  我现在能做到的是实现背景色占满SubItem一半区域, 但文字一上去就冲掉, 我考虑的是有没有什么异或的涂色或写文字的方法, 但还没试出来.
 
  这个问题弄了我快1天的时间了,郁闷ING!
2005-01-13 12:17:23回复人: yuanbocsut
帮你顶,不懂
2005-01-13 13:35:39回复人: microibm
我现在有了些进展,
取得某个SubItem的CRect,
然后根据取得的CRect,定制自己的一个要填充背景色的CRect,
填色, 然后设置Text Mode为透明, 将文字显示出来,这样就能达到我要的那种效果.

但现在还有个问题,原来CListCtrl中有很多数据,一旦进行上面的操作进行填色后,原来的数据全消失了, 也不知道那个地方的问题,可能导致了重画, 正解决中.......
2005-01-13 15:33:30回复人: chuanke
关注着
2005-01-13 15:55:33回复人: sjhunter
我那段代码可以呀,我当初做的ListCtrl控件可麻烦了,你的这个要求用这段代码可以实现。
首先:NM_CUSTOMDRAW是不能在Class Wizard中添加的,但是它不是自定义消息,你可以查一查MSDN
其次:你只要在case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:里做就可以了,首先添颜色,然后SetBKMode,再GetItemText,然后DrawText
至于你是ListView,你可能需要SubclassWindow一下,将它的ListCtrl挂在你自己的ListCtrl下
2005-01-13 16:09:58回复人: mousefj
还可以派生CListView类,重载DrawItem(),这个也很方便,如果有兴趣可以告诉我你的mail,我给你邮过去我的过去的类似代码和一片文章。
2005-01-13 16:47:02回复人: microibm
mousefj:
   你说的方法我找到了, 重载一个CListView类,在DrawItem()处理.

 在重载的DrawItem()中加一段代码,的确可以达到我要的效果,不过好像很难从外部控制.即,DrawItem我们可以主动调用它吗? 好像不行啊,它好像是被框架调用的.那样的话,我要指定的一些参数好像很难传进去啊?(如我要指定画的背景的颜色,宽度等)
   如果背景颜色的设置只是一遍就完的话,好像DrawItem()中加段代码就可以了,不过我的背景色要根据不同情况人为去设的呀!?

sjhunter:
  还没来得及非常仔细地看你的CODE,先想问一下,你的那种做法,能通过传参数什么的,人为不断地去指定颜色吗?

    对关注本帖者,非常感谢! 愿各位新的一年中,快乐平安!
2005-01-13 17:34:56回复人: galaxy_fxstar
关注zhong ......
2005-01-13 17:57:33回复人: mousefj
DrawItem是在ListView刷新是调用现实每一个Item。我建议在新的派生类中加入一个CList,用于保存每个Item的颜色信息,定义如下:
CList<ITEM_APPEND_ATTR,ITEM_APPEND_ATTR&> ItemAppendAttr;   //save all itemColor
其中ITEM_APPEND_ATTR的定义如下:
typedef struct Item_Append_Attr
{
COLORREF BKColor;
char ItemLever;
BOOL IsLeverFirst;
BOOL IsOpen;
}ITEM_APPEND_ATTR;
然后添加函数BOOL SetItemColor(int vnItemIndex,COLORREF vdwItemColor);
BOOL CSwithListCtrl::SetItemColor(int vnItemIndex, COLORREF vdwItemColor)
{
if(vnItemIndex>=GetItemCount())
return FALSE;
POSITION pos=ItemAppendAttr.FindIndex(vnItemIndex);
ITEM_APPEND_ATTR m_ItemAppendAttr;
m_ItemAppendAttr=ItemAppendAttr.GetAt(pos);
m_ItemAppendAttr.BKColor=vdwItemColor;
ItemAppendAttr.SetAt(pos,m_ItemAppendAttr);
return TRUE;
}
这个函数外部可调用。
在DrawItem()中设置文本的地方加入以下代码即可实现
CRect rcClient, rcRow = rcItem;
GetClientRect(&rcClient);
rcRow.right = rcClient.right;
COLORREF m_colorItem;
if(nItem==m_nCurItemIndex)
    m_colorItem=RGB(88,167,169);
else
    m_colorItem=ItemAppendAttr.GetAt(ItemAppendAttr.FindIndex(nItem)).BKColor;
pDC->FillRect(rcItem, &CBrush(m_colorItem));//;RGB(120,255,255)

我已实现了非常好用
2005-01-13 19:41:10回复人: microibm
mousefj:
    非常感谢你的指导! 按照你的思路, 我已经搞定了!

sjhunter:
   也非常谢谢你, 等有了喘息的机会,我也试试你说的方法.

其余各位:
   多谢各位关注, 大家一起提高!
================================================================================


http://book.77169.org/54/26717.htm
如何使listctrl每一行的颜色都不同
--------------------------------------------------------------------------------

在对话框的界面上放置了一个CListCtrl,并设置成report形式,现在想让不同的行显示不同的颜色,不知道该怎么做?
请各位高手知道

--------------------------------------------------------------------------------

自己重绘
处理WM_OWNERDRAW消息

--------------------------------------------------------------------------------

up

--------------------------------------------------------------------------------

http://www.vccode.com/file_show.php?id=703

--------------------------------------------------------------------------------

WM_OWNERDRAW在什么地方,我怎么找不到呀?

--------------------------------------------------------------------------------

http://www.vckbase.com/document/viewdoc.asp?id=891

--------------------------------------------------------------------------------

ding

--------------------------------------------------------------------------------

自绘比较灵和!

--------------------------------------------------------------------------------

设置控件的自绘制属性OwnerDraw,重载DrawItem()函数

--------------------------------------------------------------------------------

这个好像只能通过自绘来实现了 :(

--------------------------------------------------------------------------------

重新写一个CExListCtrl
重载OnCustomDraw
代码如下:
void CExListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR;
switch(lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
*pResult = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
*pResult = CDRF_NOTIFYSUBITEMDRAW;
break;
case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
{
int iColumn = lplvcd->iSubItem;
int iRow = (int) lplvcd->nmcd.dwItemSpec;
lplvcd->clrTextBk =RGB(255,255,255);
lplvcd->clrText = RGB(0,0,255);
if (iColumn == m_iSortedColumn && m_bMarkSortedColumn &&
lplvcd->clrTextBk == GetBkColor ())
{
lplvcd->clrTextBk = m_clrSortedColumn;
}
}
*pResult = CDRF_DODEFAULT;
break;
/*
case CDDS_POSTERASE:
{
CDC *pDC=CDC::FromHandle(lplvcd->nmcd.hdc);
CRect rc;
rc.CopyRect(&lplvcd->nmcd.rc);
pDC->FillSolidRect(&rc,RGB(0,0,0));
}
*pResult=CDRF_SKIPDEFAULT;
break;
*/
}

}

--------------------------------------------------------------------------------

通过处理NM_CUSTOMDRAW,可以实现你的功能!但是NM_CUSTOMDRAW在Class Wizard中有可能看不到,不用管他,直接按照小面的方法添加处理过程即可!
1. 在消息映射表中
BEGIN_MESSAGE_MAP(CIHISSERVERView, CListView)
//{{AFX_MSG_MAP(CIHISSERVERView)
...
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
...
//}}AFX_MSG_MAP
// Standard printing commands
END_MESSAGE_MAP()
2.在头文件中
afx_msg void OnCustomDraw(NMHDR*, LRESULT*);
3.在cpp文件中
void CIHISSERVERView::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
// Contains information specific to an NM_CUSTOMDRAW
// notification message sent by a list-view control.
// mean:draw each item.set txt color,bkcolor....
NMLVCUSTOMDRAW* pLVCD = (NMLVCUSTOMDRAW*)(pNMHDR);
// Take the default processing unless we set this to something else below.
*pResult = CDRF_NEWFONT;
// First thing - check the draw stage. If it's the control's prepaint
// stage, then tell Windows we want messages for every item.
if ( pLVCD->nmcd.dwDrawStage==CDDS_PREPAINT)
{
*pResult = CDRF_NOTIFYITEMDRAW;
}
// This is the notification message for an item. We'll request
// notifications before each subitem's prepaint stage.
else if ( pLVCD->nmcd.dwDrawStage==CDDS_ITEMPREPAINT )
{
COLORREF m_crTextBk , m_clrText;
int nItem = static_cast (pLVCD->nmcd.dwItemSpec);


// 判断使ListCtrl不同颜色现实的条件
CListCtrl &m_list = GetListCtrl();
CString str1 = m_list.GetItemText(nItem ,15);

bool bDBImplFail = false ;
if (str1 == "信息不祥")
{
m_crTextBk = RGB(255, 255, 0) ;
m_clrText = RGB(128, 0, 128) ;
}
else
{
m_crTextBk = RGB(150, 255, 255);
m_clrText = RGB(12,26,234);
}

pLVCD->clrTextBk = m_crTextBk;
pLVCD->clrText = m_clrText;
*pResult = CDRF_DODEFAULT;
}
}

原创粉丝点击