转载注明出处
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; }
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);
那么视图位置就会切换了
垂直同理
涉及内容和代码比较多,可能叙述不是很详尽 , 个人觉得提供思路比将全部代码贴出来好,有兴趣的话可以去研究一下。