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