MFC:拖动滚动条拇指时的奇怪行为
MFC: strange behavior when dragging scrollbar thumb
我使用滚动条显示大量多行数据(一些背景请参考我之前的问题:MFC: how to reduce the time cost of OnInitialUpdate() for scrolling?)。
滚动功能在以下情况下工作正常:(1) 单击箭头按钮,(2) 单击滚动轴或 (3) 滚动鼠标滚轮;内容正确向上或向下移动。但是当我拖动滚动拇指时,除非距离非常小,否则它的行为并不像预期的那样。
再拖一点点,例如向前,它可能会向后跳,有时会一直跳到开头。当鼠标松开时它永远不会停留,我也从来没有成功地将拇指一直拖到最后一条记录。
仔细一看,"GetClipBox(...)" 似乎不是 return 正确的数据。例如,如果我一直拖到最后,此函数将 return rect.top 等于零。由于我依靠 return 值来计算要绘制的记录集,所以其余的都搞砸了。
可在此处访问最小的可重现示例:https://138.197.210.223/test/My.tar.gz。测试时,将拇指一直拖到最后效果更佳。
您是否添加了WM_HSCROLL orWM_VSCROLL消息?
The WM_HSCROLL message is sent to a window when a scroll event occurs
in the window's standard horizontal scroll bar. This message is also
sent to the owner of a horizontal scroll bar control when a scroll
event occurs in the control.
The WM_VSCROLL message is sent to a window when a scroll event occurs
in the window's standard vertical scroll bar. This message is also
sent to the owner of a vertical scroll bar control when a scroll event
occurs in the control.
建议您尝试在OnHScroll函数或OnVScroll函数中加入如下代码:
case SB_THUMBPOSITION:
pScrollBar->SetScrollPos(nPos);
break;
这是由于 16-bit limit of the WM_VSCROLL message。实际上,限制是 32767,而不是文档中所说的 65535。很久以前在一个项目中遇到了同样的问题。
解决方法是修改 WM_VSCROLL
消息处理,使其使用 GetScrollInfo()
函数返回的 32 位值。覆盖 OnVScroll()
(转到 Class 查看,select 您的视图并添加 WM_VSCROLL
消息处理程序):
void CMyView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// Workaround the 16-bit limitation
if (nSBCode == SB_THUMBPOSITION || nSBCode == SB_THUMBTRACK)
{
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
::GetScrollInfo(m_hWnd, SB_VERT, &si);
// Set nPos to the 32-bit value
nPos = si.nTrackPos;
}
CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
}
这应该可以解决问题。
我使用滚动条显示大量多行数据(一些背景请参考我之前的问题:MFC: how to reduce the time cost of OnInitialUpdate() for scrolling?)。
滚动功能在以下情况下工作正常:(1) 单击箭头按钮,(2) 单击滚动轴或 (3) 滚动鼠标滚轮;内容正确向上或向下移动。但是当我拖动滚动拇指时,除非距离非常小,否则它的行为并不像预期的那样。
再拖一点点,例如向前,它可能会向后跳,有时会一直跳到开头。当鼠标松开时它永远不会停留,我也从来没有成功地将拇指一直拖到最后一条记录。
仔细一看,"GetClipBox(...)" 似乎不是 return 正确的数据。例如,如果我一直拖到最后,此函数将 return rect.top 等于零。由于我依靠 return 值来计算要绘制的记录集,所以其余的都搞砸了。
可在此处访问最小的可重现示例:https://138.197.210.223/test/My.tar.gz。测试时,将拇指一直拖到最后效果更佳。
您是否添加了WM_HSCROLL orWM_VSCROLL消息?
The WM_HSCROLL message is sent to a window when a scroll event occurs in the window's standard horizontal scroll bar. This message is also sent to the owner of a horizontal scroll bar control when a scroll event occurs in the control.
The WM_VSCROLL message is sent to a window when a scroll event occurs in the window's standard vertical scroll bar. This message is also sent to the owner of a vertical scroll bar control when a scroll event occurs in the control.
建议您尝试在OnHScroll函数或OnVScroll函数中加入如下代码:
case SB_THUMBPOSITION:
pScrollBar->SetScrollPos(nPos);
break;
这是由于 16-bit limit of the WM_VSCROLL message。实际上,限制是 32767,而不是文档中所说的 65535。很久以前在一个项目中遇到了同样的问题。
解决方法是修改 WM_VSCROLL
消息处理,使其使用 GetScrollInfo()
函数返回的 32 位值。覆盖 OnVScroll()
(转到 Class 查看,select 您的视图并添加 WM_VSCROLL
消息处理程序):
void CMyView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// Workaround the 16-bit limitation
if (nSBCode == SB_THUMBPOSITION || nSBCode == SB_THUMBTRACK)
{
SCROLLINFO si;
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
::GetScrollInfo(m_hWnd, SB_VERT, &si);
// Set nPos to the 32-bit value
nPos = si.nTrackPos;
}
CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
}
这应该可以解决问题。