VC自绘滚动条

来源:互联网 发布:xen跟linux是什么关系 编辑:程序博客网 时间:2024/06/05 21:16

转载注明出处

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 pageint 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 posint 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);

那么视图位置就会切换了

垂直同理

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