坎坷WTL行(二)重绘CListViewCtrl之二

在上一篇博客中介绍了CListViewCtrl的重绘,但发现无法去除网格线。通过查找资料,找到了一种巧妙的方法:复制竖线右侧像素至左侧实现效果。文章详细讲述了实现过程,包括响应Print消息的代码,并解决了链接错误LNK1000的问题。通过调整链接器设置和C/C++的调试信息格式,成功解决警告。虽未能安装KB948127补丁,但从补丁中提取link.exe文件解决了问题。资源链接已提供。

上一篇提完了重绘了CListViewCtrl,后来我想不需要网格线,结果发现一个问题,如果加双缓冲之后,不管怎么样都会有网格线,在网上又找了好久,发现一篇可以重改网络线颜色的日志,于是想到一个有意思的方法。复制竖线右侧一个像素的到左侧,完成效果。

原样式:

修改后样式:

响应Print消息,代码如下:

LRESULT CMdListViewCtrl::OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	//// TODO: 在此添加消息处理程序代码和/或调用默认值
	DefWindowProc();

	// Draw the lines only for LVS_REPORT mode
	if( (GetStyle() & LVS_TYPEMASK) == LVS_REPORT )
	{
		// Get the number of columns
		CClientDC dc(this->m_hWnd);
		RECT rect;
		//this->GetClientRect(&rect);
		//dc.FillRect(&rect,RGB(255,255,255));
		int nColumnCount = m_headerCtrl.GetItemCount();

		// The bottom of the header corresponds to the top of the line 
		//RECT rect;
		m_headerCtrl.GetClientRect( &rect );
		int top = rect.bottom;

		// Now get the client rect so we know the line length and
		// when to stop
		GetClientRect( &rect );

		// The border of the column is offset by the horz scroll
		int borderx = 0 - GetScrollPos( SB_HORZ );
		dc.SelectPen((HPEN)GetStockObject(DC_PEN)); 
		dc.SetDCPenColor(RGB(255,255,255));
		for( int i = 0; i < nColumnCount; i++ )
		{
			// Get the next border
			borderx += GetColumnWidth( i );

			// if next border is outside client area, break out
			if( borderx >= rect.right ) break;

			// Draw the line.
			dc.BitBlt( borderx, top, 1, rect.bottom - rect.top, dc , borderx + 1, top, SRCCOPY);
			//dc.MoveTo( borderx, top);
			//dc.LineTo( borderx, rect.bottom );
		}

		// Draw the horizontal grid lines

		// First get the height
		if( !GetItemRect( 0, &rect, LVIR_BOUNDS ))
			return 0;

		int height = rect.bottom - rect.top;

		GetClientRect( &rect );
		int width = rect.right;
		//dc.SelectPen((HPEN)GetStockObject(DC_PEN)); 
		dc.SetDCPenColor(RGB(170,170,170));
		for( int i = 1; i <= GetCountPerPage(); i++ )
		{
			dc.MoveTo( 0, top + height*i-1);
			dc.LineTo( width, top + height*i-1 );
		}
	}

	return 0;
}

另外还重绘了表头,使用了以下类:

class CMdHeader:public CWindowImpl<CMdHeader,CHeaderCtrl>, public COwnerDraw<CMdHeader>
{
public:

	BEGIN_MSG_MAP(CMdHeader)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
		//MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
		MESSAGE_HANDLER(HDM_LAYOUT, OnHDMLayout)
		CHAIN_MSG_MAP_ALT(COwnerDraw<CMdHeader>, 1) //将消息反射给自己  1  有父类处理消息 0
		DEFAULT_REFLECTION_HANDLER()
	END_MSG_MAP()
public:
	CMdHeader()
	{
		m_nHeight = 25;
	}
	~CMdHeader()
	{

	}
public:
	int m_nHeight;
	LRESULT OnPaint(UINT , WPARAM , LPARAM , BOOL& )
	{
		CPaintDC dc(m_hWnd);
		RECT rect,rectItem;
		::GetClientRect(m_hWnd,&rect);
		//TRIVERTEX tv[] = {
		//	{ rect.left, rect.top,0x8500,0x8500,0x8500},
		//	{ rect.right, rect.bottom-13, 0x5a00,0x5a00,0x5a00}
		//};
		//GRADIENT_RECT gr = { 0, 1 };
		//dc.GradientFill ( tv, 2, &gr, 1, GRADIENT_FILL_RECT_V );
		//TRIVERTEX tvs[] = {
		//	{ rect.left, rect.top+15,0,0,0},
		//	{ rect.right, rect.bottom, 0,0,0}
		//};
		//dc.GradientFill ( tvs, 2, &gr, 1, GRADIENT_FILL_RECT_V );
		dc.FillSolidRect(&rect, RGB(255, 255, 255));
		dc.MoveTo(0,rect.bottom-1);
		dc.LineTo(rect.right,rect.bottom-1);
		int nItems = GetItemCount();
		HDITEM hdi;
		TCHAR  lpBuffer[256]={0};
		UINT uFormat = DT_SINGLELINE|DT_CENTER|DT_VCENTER;//DT_SINGLELINE | DT_NOPREFIX | DT_TOP |DT_CENTER | DT_END_ELLIPSIS;

		dc.SelectFont( HFONT( GetStockObject( DEFAULT_GUI_FONT)));
		for(int i = 0;i<nItems;i++) //最后一个分割标志不用画
		{
			GetItemRect(i, &rectItem);
			hdi.mask = HDI_TEXT;
			hdi.pszText = lpBuffer;
			hdi.cchTextMax = 256;

			GetItem(i, &hdi);
			dc.SetTextColor(RGB(0,0,0));
			dc.SetBkMode(TRANSPARENT);
			CString str = lpBuffer;
			dc.DrawText(str,str.GetLength(),&rectItem,uFormat);
			memset(lpBuffer,0,256);
		}
		return 0;
	}

	LRESULT OnHDMLayout(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		LRESULT lResult = CWindowImpl<CMdHeader, CHeaderCtrl>::DefWindowProc(uMsg, wParam, lParam);
		HD_LAYOUT &hdl = *( HD_LAYOUT * ) lParam;
		RECT *prc = hdl.prc;
		WINDOWPOS *pwpos = hdl.pwpos;
		int nHeight = (int)(pwpos->cy);
		if(m_nHeight>=0)
			nHeight = m_nHeight;
		pwpos->cy = nHeight;
		prc->top = nHeight;
		return lResult;
	}
	//LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
	//{
	//	LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam;
	//	lpMeasureItemStruct->itemHeight = 25;
	//	return (LRESULT)TRUE;
	//}
	void DrawItem(LPDRAWITEMSTRUCT lpdis)
	{
		//::MessageBox(NULL,L"qqq",L"111",MB_OK);
	}
	void DeleteItem(LPDELETEITEMSTRUCT lpdis)
	{

	}
	void SetStyle() 
	{
		HDITEM hdItem;
		hdItem.mask = HDI_FORMAT;
		for(int i=0; i<this->GetItemCount(); i++)
		{
			this->GetItem(i,&hdItem);
			hdItem.fmt|= HDF_OWNERDRAW;  
			this->SetItem(i,&hdItem);
		}
		CFont m_NewHeaderFont;
		m_NewHeaderFont.CreatePointFont(300,L"宋体");
		this->SetFont(m_NewHeaderFont);
		m_NewHeaderFont.DeleteObject();
		//ModifyStyle(HDS_BUTTONS, 0);
	}

};

在::OnCreate子类化:

	//子类化表头
	m_headerCtrl.SubclassWindow(this->GetHeader().m_hWnd);
	m_headerCtrl.SetStyle();

在使用WIN7编译时,还遇到一个问题,VS2008在编译时总报错误,在网上到到解决方法:

错误:LINK : fatal error LNK1000: Internal error during IncrBuildImage
解决办法:
项目->属性->链接器->常规 下面的“启用增量链接”,将“是(/INCREMENTAL)”改为“否(/INCREMENTAL:NO)”。
不过这又引入了另外一个警 告:FormatCom.obj : warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/INCREMENTAL:NO”规范)
选择项目,属性->配置属性 ->C/C++,修改“调试信息格式”为“程序数据库(/Zi)”即可。
到此问题解决,据说这是VC的一个内部BUG,可以下载KB948127补丁来解决,但我并没有能正常安装该补丁。
下载补丁地址:http://code.msdn.microsoft.com/KB948127
虽然不然安装,但是我从这个补丁中提取出了link.exe替换相应文件,问题解决。

我把这个link.exe上传到资源:http://download.csdn.net/detail/lymcn/3859078


评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值