防止CListCtrl闪烁的几种方法

1. 使用SetRedraw禁止窗口重绘,操作完成后,再恢复窗口重绘

m_ctlList.SetRedraw(FALSE);
//以下为更新数据操作
//……
//恢复窗口重绘
m_ctlList.SetRedraw(TRUE);

2. 使用LockWindowUpdate禁止窗口重绘,操作完成后,用UnlockWindowUpdate恢复窗口重绘

m_ctlList.LockWindowUpdate();
//以下为更新数据操作
//……
//恢复窗口重绘
m_ctlList.UnlockWindowUpdate();

3. 使用ListCtrl的内部双缓冲(经实测, 好像不起作用)

m_ctlLisit.SetExtendedStyle(m_ctlLisit.GetExtendedStyle()|LVS_EX_DOUBLEBUFFER);
VC6未定义LVS_EX_DOUBLEBUFFER宏,使用者可以自定义,如下:
#define LVS_EX_DOUBLEBUFFER 0×00010000


4. Virtual List

首先要设置ListCtrl风格为LVS_REPORT | LVS_OWNERDATA或在ListCtrl属里中的More Styles页面中选中Owner data复选框。
其次要向应LVN_GETDISPINFO消息;
void OnGetdispinfoList(NMHDR* pNMHDR, LRESULT* pResult)
{
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
	LV_ITEM *pItem = &(pDispInfo)->item;
	char szText[128] = {0};
	
	if (pItem->mask & LVIF_TEXT)
	{
		//使缓冲区数据与表格子项对应
		//m_ArrayBuff为二维数组
		//定义如下 int m_ArrayBuff[2048][4];
		_stprintf(szText,_T(“%d”),m_ArrayBuff[pItem->iItem][pItem->iSubItem]);
		pItem->pszText = szText;
	}
	
	*pResult = 0;
	}
	
	最后便是生成缓冲区数据
	void Insertdata()
	{
		//删除之前的数据
		m_ctlList.SetItemCountEx(0);
		m_ctlList.Invalidate();
		m_ctlList.UpdateWindow();
		srand( (unsigned)time( NULL ));
		
		//生成新的数据缓冲区
		int nItemCount = 2048;
		for (int i = 0;i < nItemCount; i ++)
		{
		for (int k = 0;k < 4;k ++)
		{
			m_ArrayBuff[i][k] = rand()%2048 + 1;
		}
	}
	
	if (nItemCount < 2)
	{
		m_ctlList.SetItemCountEx(1);
	}
	else
	{
		m_ctlList.SetItemCountEx(nItemCount);
	}
	
	m_ctlList.Invalidate();
}
若要修改数据,只要修改缓冲区m_ArrayBuff的数据即可以



5.  自绘(最常用,最简单)

首先当然是重载CListCtrl类,设置ListCtrl属性"Owner Draw Fixed"为true,"Owner data"为false

(1).  并接管WM_ERASEBKGND消息,去掉默认的处理,改为不处理

手动添加重载消息ON_WM_ERASEBKGND()

BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC)
{
//响应WM_ERASEBKGND消息
return false;
//屏蔽默认处理
//return CListCtrl::OnEraseBkgnd(pDC);
}

(2). 手动添加重载消息ON_WM_DRAWITEM()

void CListCtrlEx::OnPaint()
{
//响应WM_PAINT消息
CPaintDC dc(this); // device context for painting
CRect rect;
CRect headerRect;
CDC MenDC;//内存ID表
CBitmap MemMap;
GetClientRect(&rect);
GetDlgItem(0)->GetWindowRect(&headerRect);
MenDC.CreateCompatibleDC(&dc);
MemMap.CreateCompatibleBitmap(&dc,rect.Width(),rect.Height());
MenDC.SelectObject(&MemMap);
MenDC.FillSolidRect(&rect,RGB(228,236,243));
//这一句是调用默认的OnPaint(),把图形画在内存DC表上
DefWindowProc(WM_PAINT,(WPARAM)MenDC.m_hDC,(LPARAM)0);
//输出
dc.BitBlt(0,headerRect.Height(),rect.Width(), rect.Height(),&MenDC,0, headerRect.Height(),SRCCOPY);
MenDC.DeleteDC();
MemMap.DeleteObject();
}

(3). 手动添加重载消息ON_WM_MEASUREITEM_REFLECT()

void DrawItem(_In_ LPDRAWITEMSTRUCT lpDrawItemStruct);

例如:这是我自己的的代码,可能你们有些符号找不到,这方面有疑问的话,可以咨询我QQ173708459,大家共同探讨

void CMyListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	LVITEM lvi = { 0 };
	lvi.mask = LVIF_STATE | LVIF_IMAGE; 
	lvi.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
	lvi.iItem = lpDrawItemStruct->itemID; //表示菜单项ID,也可以表示列表框或者组合框中某项的索引值
	BOOL bGet = GetItem(&lvi); //获取某些或全部列表视图项的属性


	//颜色变量
	COLORREF cTextColor;
	COLORREF cBackColor;

	//绘制区域
	CRect rcBack = lpDrawItemStruct->rcItem;
	int nWidth = rcBack.Width();
	int nHeight = rcBack.Height();

	//偏移图标位置(44*44),避免选中行时图标也被选中
	rcBack.left += 48;
	pDC->SetBkMode(TRANSPARENT);

	//统一字体
	CFont* OldFont = (CFont*)pDC->SelectObject(m_Font); //预先设置文本字体

	//判断是否选中
	BOOL bHighlight = ((lvi.state & LVIS_DROPHILITED) || ((lvi.state & LVIS_SELECTED) && ((GetFocus() == this) || (GetStyle() & LVS_SHOWSELALWAYS))));

	//(1).先设置文本及背景色 
	if (bHighlight) //选中行
	{
		cTextColor = m_SelectItemTextColor;
		cBackColor = m_SelectItemBackColor;
	}
	else if (lvi.iItem == m_nHoverIndex) //热点行
	{
		cTextColor = m_HoverItemTextColor;
		cBackColor = m_HoverItemBackColor;
	}
	else
	{
		if (lpDrawItemStruct->itemID % 2) //奇数行
		{
			cTextColor = m_OddItemTextColor;
			cBackColor = m_OddItemBackColor;
		}
		else //偶数行
		{
			cTextColor = m_EvenItemTextColor;
			cBackColor = m_EvenItemBackColor;
		}
	}

	//(2).再统一绘制颜色
	pDC->SetTextColor(cTextColor);
	pDC->FillRect(rcBack, &CBrush(cBackColor));

	//(3).绘制文本内容
	if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE)
	{
		//获取列数
		CString szText;
		int nCollumn = GetHeaderCtrl()->GetItemCount();

		//循环得到文本 
		for (int i = 0; i < nCollumn; i++)
		{ 
			//获取子项矩形边界 
			CRect rcItem;
			if (!GetSubItemRect(lvi.iItem, i, LVIR_LABEL, rcItem))
			{
				continue;
			}

			//获取子项文本内容
			szText = GetItemText(lvi.iItem, i);

			//绘制按钮
			if (m_nListMark == LIST_INSTALL)
			{
				strTask_S *pTask = (strTask_S*)lpDrawItemStruct->itemData;
				if (NULL != pTask)
				{
					if (i == 3)  //绘制进度条
					{
						CRect rect(pTask->strProgress.rect);
						if (!rect.IsRectEmpty())
						{
							//绘制边框
							//CPoint point(5, 5);
							CPen hNewPen(PS_SOLID, 1, RGB(217, 0, 0)); //RGB(217, 217, 217)
							CPen* hOldPen = pDC->SelectObject(&hNewPen);
							//pDC->RoundRect(&rect, point);
							pDC->Rectangle(rect);
							pDC->SelectObject(hOldPen);
							hNewPen.DeleteObject();

							//填充颜色
							rect.top += 1;
							rect.left += 1;
							rect.right -= 1;
							rect.bottom -= 1;

							CString sInfo = "";
							sInfo.Format("2.....%d\r\n", pTask->strProgress.uPercent);
							OutputDebugString(sInfo);
							int nLen = pTask->strProgress.uPercent * rect.Width() / 100;
							sInfo.Format("3.....%d\r\n", nLen);
							OutputDebugString(sInfo);

							rect.right = rect.left + nLen;
							CBrush brush(RGB(31, 210, 69));
							pDC->FillRect(&rect, &brush);
							//brush.DeleteObject();

							//绘制文本
							CRect rcText(pTask->strProgress.rect);
							rcText.top = rcText.bottom + 8;
							rcText.bottom = rcText.top + 13;
							pDC->SetTextColor(RGB(153, 153, 153));
							pDC->DrawText("已下载 0 B, 0 B/s", &rcText, DT_LEFT | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE);
						}
					}
					else if (i == 4)  //绘制按钮
					{
						if (!pTask->strButtons.rect.IsRectEmpty())
						{
							//按钮边框
							CPoint point(6, 6);
							CPen hNewPen(PS_SOLID, 1, RGB(153, 153, 153));
							CPen* hOldPen = pDC->SelectObject(&hNewPen);
							CRect rect(pTask->strButtons.rect);
							pDC->RoundRect(rect, point);
							pDC->SelectObject(hOldPen);
							hNewPen.DeleteObject();

							//向内缩进
							rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));

							//改用GDI+绘制,目的填充按钮渐变色
							//定义一个线性渐变画刷,沿直线方向渐变,从上往下渐变
							Point point1(rect.left, rect.top);
							Point point2(rect.left, rect.bottom);
							LinearGradientBrush linGrBrush(point1, point2, Color(255, 248, 248, 248), Color(255, 210, 210, 210));
							Color colors[] = { Color(255, 220, 220, 220), Color(255, 200, 200, 200) }; //按红两种颜色渐变
							REAL positions[] = { 0.0f, 0.5f }; //两种颜色,各占二分之一
							linGrBrush.SetInterpolationColors(colors, positions, 2); //设置插补颜色(插值法)
							Gdiplus::Graphics graphics(pDC->m_hDC);
							graphics.FillRectangle(&linGrBrush, rect.left, rect.top, rect.Width(), rect.Height()); //填充区域 

							//绘制文本
							Gdiplus::Pen pen(Gdiplus::Color(255, 0, 0, 255));
							Gdiplus::SolidBrush brush(Gdiplus::Color(255, 30, 30, 30)); //设置颜色和透明(0完全透明)/R/G/B
							Gdiplus::FontFamily family(L"微软雅黑"); //设置字体 FontFamily fontFamily(L"Arial");
							Gdiplus::Font font(&family, (Gdiplus::REAL)12, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); //FontStyleBold:粗体;FontStyleItalic:斜体;FontStyleUnderline:下划线
							Gdiplus::PointF pointF((Gdiplus::REAL)rect.left + 12, (Gdiplus::REAL)rect.top + 2);
							graphics.DrawString(CT2CW(pTask->strButtons.sTitle), -1, &font, pointF, &brush);
						}
					}
					else  //绘制文本
					{
						if (0 == i)
						{
							rcItem.left += 48 + 5;  //跳过图标位置
						}

						pDC->DrawText(szText, lstrlen(szText), &rcItem, DT_LEFT | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE);
					}
				}
			}
			else if (m_nListMark == LIST_UPGRADE)
			{
				strAppInfo_S *pAppInfo = (strAppInfo_S*)lpDrawItemStruct->itemData;
				if (NULL != pAppInfo)
				{
					if (i == 2) //设置按钮
					{
						if (!pAppInfo->strButtons.rect.IsRectEmpty())
						{
							//按钮边框
							CPoint point(6, 6);
							CPen hNewPen(PS_SOLID, 1, RGB(153, 153, 153));
							CPen* hOldPen = pDC->SelectObject(&hNewPen);
							CRect rect(pAppInfo->strButtons.rect);
							pDC->RoundRect(rect, point);
							pDC->SelectObject(hOldPen);
							hNewPen.DeleteObject();

							//向内缩进
							rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));

							//改用GDI+绘制,目的填充按钮渐变色
							//定义一个线性渐变画刷,沿直线方向渐变,从上往下渐变
							Point point1(rect.left, rect.top);
							Point point2(rect.left, rect.bottom);
							LinearGradientBrush linGrBrush(point1, point2, Color(255, 248, 248, 248), Color(255, 210, 210, 210));
							Color colors[] = { Color(255, 220, 220, 220), Color(255, 200, 200, 200) }; //按红两种颜色渐变
							REAL positions[] = { 0.0f, 0.5f }; //两种颜色,各占二分之一
							linGrBrush.SetInterpolationColors(colors, positions, 2); //设置插补颜色(插值法)
							Gdiplus::Graphics graphics(pDC->m_hDC);
							graphics.FillRectangle(&linGrBrush, rect.left, rect.top, rect.Width(), rect.Height()); //填充区域 

							//绘制文本
							Gdiplus::Pen pen(Gdiplus::Color(255, 0, 0, 255));
							Gdiplus::SolidBrush brush(Gdiplus::Color(255, 30, 30, 30)); //设置颜色和透明(0完全透明)/R/G/B
							Gdiplus::FontFamily family(L"微软雅黑"); //设置字体 FontFamily fontFamily(L"Arial");
							Gdiplus::Font font(&family, (Gdiplus::REAL)12, Gdiplus::FontStyleRegular, Gdiplus::UnitPixel); //FontStyleBold:粗体;FontStyleItalic:斜体;FontStyleUnderline:下划线
							Gdiplus::PointF pointF((Gdiplus::REAL)rect.left + 12, (Gdiplus::REAL)rect.top + 2);
							graphics.DrawString(CT2CW(pAppInfo->strButtons.sTitle), -1, &font, pointF, &brush);
						}
					}
					else  //绘制文本
					{
						if (0 == i)
						{
							rcItem.left += 48 + 5;  //跳过图标位置
						}

						pDC->DrawText(szText, lstrlen(szText), &rcItem, DT_LEFT | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE);
					}
				}
			}
		}
	}

	//(4).重绘图标
	Graphics graphics(pDC->m_hDC);
	if (m_nListMark == LIST_INSTALL)
	{
		strTask_S *pTask = (strTask_S*)this->GetItemData(lvi.iItem);

		if (pTask && pTask->pImageIcon)
		{
			Image *pImage = pTask->pImageIcon;
			if (pImage)
			{
				graphics.DrawImage(pImage, 6, rcBack.top + 5, 36, 36);
			}
		}
		else
		{
			graphics.DrawImage(g_pDefaultIcon, 6, rcBack.top + 5, 36, 36);
		}
	}
	else if (m_nListMark == LIST_UPGRADE)
	{
		strAppInfo_S *pTask = (strAppInfo_S*)this->GetItemData(lvi.iItem);

		if (pTask && pTask->pImageIcon)
		{
			Image *pImage = pTask->pImageIcon;
			if (pImage)
			{
				graphics.DrawImage(pImage, 6, rcBack.top + 5, 36, 36);
			}
		}
		else
		{
			graphics.DrawImage(g_pDefaultIcon, 6, rcBack.top + 5, 36, 36);
		}
	}
}





你可能感兴趣的:(防止CListCtrl闪烁的几种方法)