VC自绘滚动条

转载注明出处

http://blog.csdn.net/xugangjava/article/details/8147386

绘制系统内建的滚动条有两种方法

1.隐藏内建滚动条 然后在父窗口绘制 挡住原有的滚动条,详细可以参考这里

http://blog.sina.com.cn/s/blog_4c3538470100gews.html


2.使用HOOK 拦截 SetScrollInfo。

一直觉得wxpython没有好的皮肤库,本着学习的态度,准备在业余时间写一个支持wxpython的皮肤库。一切处于开始阶段。

为了不影响原有的代码设计,采用dll加载,使用HOOK拦截Windows消息,执行自绘制。

所以这里主要介绍第二种方法来绘制滚动条。

http://msdn.microsoft.com/zh-cn/library/windows/desktop/bb787537(v=vs.85).aspx

在这里"社区附加资源" 可以看到 SetScrollInfo中使用的  SCROLLINFO 结构体必须要满足的关系。

SetScrollInfo中Windows调用滚动条重新绘制的函数。

所以只要在我们的SetScrollInfo 中维持 nMin nMax nPage  nPos 而不执行原函数,

那么系统就不会对滚动条进行绘制了。

下面我们来处理SetScrollInfo

LPSKININFO结构体来将存储滚动条信息,由我们来处理滚动条的信息

typedef struct tagSkinInfo
{
	LONG oldWndProc;
	LONG newWndProc;
	char className[64];

	RECT prevRECT;

	BOOL bTackMouseEvent;
	BOOL bNCTackMouseEvent;
	
	BOOL bMouseStillClick;


	BOOL bMouseLDown;
	BOOL bMouseIn;

	BOOL bDragingThumb;
	DRAGTHUMB dragThumb;
	int curSB;	

	
	BOOL bNCMouseLDown;
	BOOL bNCMouseIn;	

	BOOL blastMouseClick;

	HWND hWnd;
	HWND pWnd;

	SCROLLINFO vScrollInfo;
	SCROLLINFO hScrollInfo;
	BOOL bShowVScroll;
	BOOL bShowHScroll;
	SBRECTINFO sbRect;
	WINRECTINFO winRect;

} 	SKININFO ,FAR *LPSKININFO;

SetScrollInfo实现

BOOL WINAPI ZwNewGetScrollInfo(
	_In_     HWND hwnd,
	_In_     int fnBar,
	_Inout_  LPSCROLLINFO lpsi)
{

	LPSKININFO ps=GetSkinInfo(hwnd);
	if(!ps)
	{
		return g_pOldGetScrollInfo(hwnd,fnBar,lpsi);
	}
	if(SB_HORZ==fnBar)
	{
		HackGetScrollinfo(&ps->hScrollInfo,lpsi);
	}
	else if(SB_VERT==fnBar)
	{
		HackGetScrollinfo(&ps->vScrollInfo,lpsi);
	}
	else if(SB_CTL==fnBar)
	{
		
	}
	else
	{
		return g_pOldGetScrollInfo(hwnd,fnBar,lpsi);
	}
	
	return TRUE;
}

HackSetcrollInfo

int HackSetScrollinfo(LPCSCROLLINFO src,LPSCROLLINFO dest)
{
	dest->fMask=src->fMask;
	dest->cbSize=src->cbSize;

	if(src->fMask&SIF_RANGE)
	{
		dest->nMax=src->nMax;
		dest->nMin=src->nMin;
	}

	if(src->fMask&SIF_PAGE)
	{
		dest->nPage =  src->nPage;
		//check page
		int maxPage= dest->nMax - dest->nMin+1 ;
		int minPage=0;
		if ( dest->nPage >(UINT)maxPage )
		{
			dest->nPage = maxPage-1;
			dest->nPos=src->nMin;
		}
		else if(dest->nPage<(UINT)minPage)
		{
			dest->nPage = minPage;
		}
		else
		{
			dest->nPage=src->nPage;
		}
	}
	if(src->fMask&SIF_POS)
	{	
		dest->nPos=src->nPos;
		//check pos
		int minPos=dest->nMin;
		int maxPos;
		if(dest->nPage-1>0)
		{
			maxPos=dest->nMax -dest->nPage+1;
		}
		else
		{
			maxPos=dest->nMax;
		}

		if(dest->nPos<minPos)
		{
			dest->nPos=minPos;
		}
		else if(dest->nPos>maxPos)
		{
			dest->nPos=maxPos;
		}

	}
	if(src->fMask&SIF_TRACKPOS)
	{
		dest->nTrackPos=src->nTrackPos;
	}

	if(src->fMask&SIF_DISABLENOSCROLL)
	{
		dest->nPos=0;
		dest->nTrackPos=0;
	}

	if(dest->nMax-dest->nMin<=0)
	{
		dest->nPos=0;
		dest->nTrackPos=0;
	}
	return dest->nPos;
}


在GetScollInfo里面 直接取我们内存中的SCROLLINFO 信息就可以了

BOOL WINAPI ZwNewGetScrollInfo(
	_In_     HWND hwnd,
	_In_     int fnBar,
	_Inout_  LPSCROLLINFO lpsi)
{

	LPSKININFO ps=GetSkinInfo(hwnd);
	if(!ps)
	{
		return g_pOldGetScrollInfo(hwnd,fnBar,lpsi);
	}
	if(SB_HORZ==fnBar)
	{
		HackGetScrollinfo(&ps->hScrollInfo,lpsi);
	}
	else if(SB_VERT==fnBar)
	{
		HackGetScrollinfo(&ps->vScrollInfo,lpsi);
	}
	else if(SB_CTL==fnBar)
	{
		
	}
	else
	{
		return g_pOldGetScrollInfo(hwnd,fnBar,lpsi);
	}
	
	return TRUE;
}



void HackGetScrollinfo(LPCSCROLLINFO src,LPSCROLLINFO dest)
{

	if(dest->fMask&SIF_RANGE)
	{
		dest->nMax=src->nMax;
		dest->nMin=src->nMin;
	}

	if(dest->fMask&SIF_PAGE)
	{
		dest->nPage =  src->nPage;
	}

	if(dest->fMask&SIF_POS)
	{	
		dest->nPos=src->nPos;
	}

	if(dest->fMask&SIF_TRACKPOS)
	{

		dest->nTrackPos=src->nTrackPos;
	}


	dest->cbSize=src->cbSize;
}



关于绘制方面

nPage/(nMax-nMin)=滑块长度/滚动条的总长度

实现拖动,鼠标点击滑块并持续按下

SetCapture

鼠标右键UP

ReleaseCapture

如果是水平滑块 记录按下的水平X坐标 nPos 初始X 初始nPos

OnMouseMove里面

(鼠标当前X位置 - 初始X)/(滚动条滑槽长度-滚动条滑块长度)= offset /(nMax-nMin -nPage)

计算得到offset

设置nTrackPos=offset+初始nPos,

SendMessage(ps->hWnd,WM_VSCROLL,MAKEWPARAM(SB_THUMBTRACK,nTrackPos),NULL);

那么视图位置就会切换了

垂直同理

涉及内容和代码比较多,可能叙述不是很详尽 , 个人觉得提供思路比将全部代码贴出来好,有兴趣的话可以去研究一下。




你可能感兴趣的:(VC自绘滚动条)