五. 滚动条的响应代码
控件上添加了滚动条, 只是让滚动条显示, 但没有响应. 响应就是你点击滚动条时, 根据滚动条的位置, 显示对应内容, 并且你需要设置滚动条的位置.
所以响应函数需要做两件事情:
A. 设置滚动条到响应位置.(如果需要);
B. 根据滚动条的响应位置设置要显示的内容的位置.
5.1 定义滚动条位置设置函数
void CMyCtrl::SetScrollBarsPos(int nScrollBar, int nPos)
{
SCROLLINFO siSet;
siSet.cbSize = sizeof(SCROLLINFO);
siSet.fMask = SIF_POS;
siSet.nPos = nPos;
SetScrollInfo(nScrollBar, &siSet, true);
}
5.2 重载垂直滚动条响应函数
void CMyCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// 获取滚动条最新位置
SCROLLINFO siGet;
siGet.cbSize = sizeof(SCROLLINFO);
GetScrollInfo(SB_VERT, &siGet, SIF_TRACKPOS | SIF_POS | SIF_RANGE | SIF_PAGE);
switch(nSBCode)
{
case SB_THUMBPOSITION: // 拖动滚动块时产生的事件
case SB_THUMBTRACK:
{
// siGet.nTrackPos就是滚动条最新位置
// 设置滚动条最新位置
SetScrollBarsPos(SB_VERT, siGet.nTrackPos);
// 根据siGet.nTrackPos计算你的内容的显示位置, 并记录.
// 这个内容的显示位置, 在你绘制控件的时候会用到.
// 怎么计算, 你自己定
...
}
}
break;
case SB_LINEDOWN: // 点击垂直滚动条"下箭头"产生的事件
case SB_PAGEDOWN: // 点击"滚动块"与"下箭头"之间的"空白处"产生的事件
{
// 计算滚动条的最新位置
int nNewPos = siGet.nPos + 偏移值; // 偏移值是多少, 你自己定
// 设置滚动条最新位置
SetScrollBarsPos(SB_VERT, nNewPos);
// 根据siGet.nTrackPos计算你的内容的显示位置, 并记录.
// 这个内容的显示位置, 在你绘制控件的时候会用到.
// 怎么计算, 你自己定
...
}
break;
case SB_LINEUP: // 点击垂直滚动条"上箭头"产生的事件
case SB_PAGEUP: // 点击"滚动块"与"上箭头"之间的"空白处"产生的事件
{
// 计算滚动条的最新位置
int nNewPos = siGet.nPos - 偏移值; // 偏移值是多少, 你自己定
// 设置滚动条最新位置
SetScrollBarsPos(SB_VERT, nNewPos);
// 根据siGet.nTrackPos计算你的内容的显示位置, 并记录.
// 这个内容的显示位置, 在你绘制控件的时候会用到.
// 怎么计算, 你自己定
...
}
break;
case SB_TOP: // 跳到最顶
{
if(0 == siGet.nPos)
{
break;
}
else
{
SetScrollBarsPos(SB_VERT, 0);
}
}
break;
case SB_BOTTOM: // 跳到最底
{
if(siGet.nMax - siGet.nPage + 1 == siGet.nPos)
{
break;
}
else
{
SetScrollBarsPos(SB_VERT, siGet.nMax - siGet.nPage + 1);
}
}
break;
}
}
5.3 重载水平滚动条响应函数
void CMyCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
SCROLLINFO siGet;
siGet.cbSize = sizeof(SCROLLINFO);
GetScrollInfo(SB_HORZ, &siGet, SIF_TRACKPOS | SIF_POS | SIF_RANGE | SIF_PAGE);
switch(nSBCode)
{
case SB_THUMBPOSITION: // 拖动滚动块时产生的事件
case SB_THUMBTRACK:
{
// siGet.nTrackPos就是滚动条最新位置
// 设置滚动条最新位置
SetScrollBarsPos(SB_HORZ, siGet.nTrackPos);
// 根据siGet.nTrackPos计算你的内容的显示位置, 并记录.
// 这个内容的显示位置, 在你绘制控件的时候会用到.
// 怎么计算, 你自己定
...
}
}
break;
case SB_LINERIGHT: // 点击水平滚动条"右箭头"产生的事件
case SB_PAGERIGHT: // 点击"滚动块"与"右箭头"之间的"空白处"产生的事件
{
// 计算滚动条的最新位置
int nNewPos = siGet.nPos + 偏移值; // 偏移值是多少, 你自己定
// 设置滚动条最新位置
SetScrollBarsPos(SB_HORZ, nNewPos);
// 根据siGet.nTrackPos计算你的内容的显示位置, 并记录.
// 这个内容的显示位置, 在你绘制控件的时候会用到.
// 怎么计算, 你自己定
...
}
break;
case SB_LINELEFT: // 点击垂直滚动条"左箭头"产生的事件
case SB_PAGELEFT: // 点击"滚动块"与"左箭头"之间的"空白处"产生的事件
{
// 计算滚动条的最新位置
int nNewPos = siGet.nPos - 偏移值; // 偏移值是多少, 你自己定
// 设置滚动条最新位置
SetScrollBarsPos(SB_HORZ, nNewPos);
// 根据siGet.nTrackPos计算你的内容的显示位置, 并记录.
// 这个内容的显示位置, 在你绘制控件的时候会用到.
// 怎么计算, 你自己定
...
}
break;
case SB_LEFT: // 跳到最左
{
if(0 == siGet.nPos)
{
break;
}
else
{
SetScrollBarsPos(SB_HORZ, 0);
}
}
break;
case SB_RIGHT: // 跳到最右
{
if(siGet.nMax - siGet.nPage + 1 == siGet.nPos)
{
break;
}
else
{
SetScrollBarsPos(SB_HORZ, siGet.nMax - siGet.nPage + 1);
}
}
break;
}
}
5.4 鼠标滚轮滚动垂直滚动条
重载OnMouseWheel函数, 在函数内向垂直滚动条发消息即可
BOOL CMyCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
if(zDelta > 0)
{
PostMessage(WM_VSCROLL, SB_LINEUP, 0);
}
else
{
PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
}
return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}
六. CWnd::SetScrollInfo的理解
BOOL CWnd::SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw)
{
ASSERT(lpScrollInfo != NULL);
HWND hWnd = m_hWnd;
CScrollBar* pScrollBar;
if (nBar != SB_CTL && (pScrollBar = GetScrollBarCtrl(nBar)) != NULL)
{
hWnd = pScrollBar->m_hWnd;
nBar = SB_CTL;
}
lpScrollInfo->cbSize = sizeof(*lpScrollInfo);
::SetScrollInfo(hWnd, nBar, lpScrollInfo, bRedraw);
return TRUE;
}
这是CWnd::SetScrollInfo, 在里面有一个GetScrollBarCtrl调用
CScrollBar* CWnd::GetScrollBarCtrl(int) const
{
return NULL; // no special scrollers supported
}
个人理解: 你的可以使用CScrollBar添加到你的自定义控件, 然后用CScrollBar来管理你的所有与滚动条相关的东西. 此时, 你需要重载GetScrollBarCtrl函数