检查一下!这适用于任何Win32应用程序。我正在使用MFC,但我不认为它特定于该框架。
我在各种窗口上都重现了它,它似乎与样式,扩展样式或类风格无关。
以下是正在发生的事情:如果一个窗口有没有滚动条,并且我在其中一个滚动方向(例如水平)上设置了一个范围,那么其他方向(例如垂直方向)现在内部范围太大!我说“内部”因为它仍然不可见,谢天谢地,但是范围的存在使事情变得混乱。
伪代码中最直接的演示:
GetScrollInfo(SB_HORZ); // min=0, max=0 --as expected
GetScrollInfo(SB_VERT); // min=0, max=0 --as expected
SetScrollInfo(SB_HORZ, 0, 5);
GetScrollInfo(SB_HORZ); // min=0, max=5 --as expected
GetScrollInfo(SB_VERT); // min=0, max=100 --what??
亲自尝试,这太疯狂了!什么更加疯狂和令人沮丧,以及我如何在第一时间遇到这个问题,如果你尝试使用SetScrollPos()它会让你!例如,如果您在之前调用了SetScrollPos(SB_VERT, 3)
,那么GetScrollPos(SB_VERT)
将返回0,但如果我在之后执行了,那么它将返回 3 !再次注意,我们正在谈论SB_VERT,它从未被设置为具有范围!
感觉就像我必须遗漏一些东西,特别是考虑到相反的滚动条(具有这个莫名其妙的范围最大值100,在上面的例子中是垂直的)实际上并没有出现在屏幕上。
(我尝试设置/获取许多不同组合的滚动信息以尝试诊断这个疯狂的问题,但它总是回到行为,如果你没有滚动条,然后你只设置一个,那么另一个去100.)
(那个数字(100)来自哪里?)
EDIT1:以下是实际代码:
void func1(HWND hWnd)
{
// this line logs: get(h) 0(1447)->0-0,0
{ SCROLLINFO si = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE | SIF_POS }; SetLastError(0); int result = ::GetScrollInfo(hWnd, SB_HORZ, &si); TRACE(_T("get(h) %li(%li)->%li-%li,%li\n"), result, GetLastError(), si.nMin, si.nMax, si.nPage); }
// this line logs: get(v) 0(1447)->0-0,0
{ SCROLLINFO si = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE | SIF_POS }; SetLastError(0); int result = ::GetScrollInfo(hWnd, SB_VERT, &si); TRACE(_T("get(v) %li(%li)->%li-%li,%li\n"), result, GetLastError(), si.nMin, si.nMax, si.nPage); }
// this line logs: set(h) 0(0)->0-5,1
{ SCROLLINFO si = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE, 0, 5, 1 }; SetLastError(0); int result = ::SetScrollInfo(hWnd, SB_HORZ, &si, FALSE); TRACE(_T("set(h) %li(%li)->%li-%li,%li\n"), result, GetLastError(), si.nMin, si.nMax, si.nPage); }
// this line logs: get(h) 1(0)->0-5,1
{ SCROLLINFO si = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE | SIF_POS }; SetLastError(0); int result = ::GetScrollInfo(hWnd, SB_HORZ, &si); TRACE(_T("get(h) %li(%li)->%li-%li,%li\n"), result, GetLastError(), si.nMin, si.nMax, si.nPage); }
// this line logs: get(v) 1(0)->0-100,0
{ SCROLLINFO si = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE | SIF_POS }; SetLastError(0); int result = ::GetScrollInfo(hWnd, SB_VERT, &si); TRACE(_T("get(v) %li(%li)->%li-%li,%li\n"), result, GetLastError(), si.nMin, si.nMax, si.nPage); }
}
EDIT2:在此重申一下这个问题:如何处理此行为并维护模块化代码。现在我能找到解决它的唯一方法就是使用这个kludgy函数在对面条状态的check + set中包装对SetScrollInfo()的任何调用:
int MySetScrollInfo(HWND hWnd, int nBar, LPSCROLLINFO psi, BOOL bRedraw)
{
int nOppositeBar = (nBar == SB_HORZ) ? SB_VERT : SB_HORZ;
SCROLLINFO siOpposite = { sizeof(SCROLLINFO), SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS };
::GetScrollInfo(hWnd, nOppositeBar, &siOpposite);
int ans = ::SetScrollInfo(hWnd, nBar, psi, bRedraw);
if (siOpposite.nMin == siOpposite.nMax) {
DWORD dwErr = GetLastError();
::SetScrollInfo(hWnd, nOppositeBar, &siOpposite, bRedraw);
SetLastError(dwErr);
}
return ans;
}
这不可能是正确的。什么是正确的方法??
EDIT3: Blarg!这也不起作用,因为它不仅仅是当你设置的时候相反的是nil,而是当你把它设置为任何东西(包括nil)时,当BOTH刚才为零时。所以我最终做的是覆盖GetScrollInfo和SetScrollInfo。在设置时,我存储一个标志,无论调用者是否设置为nil,然后我在每个Get上检查该标志。真是一团糟。
答案 0 :(得分:1)
我能够复制声称在一个条上设置范围导致另一个条的范围初始化为0-100。
与可能导致序列错误的应用程序兼容可能会产生副作用。
至于100的来源,GetScrollRange的文档说:
标准滚动条的默认范围是0到100。
"标准"在此上下文中,表示非客户区滚动条之一,而不是子滚动条控件。