考虑一个带有WS_HSCROLL
和/或WS_VSCROLL
滚动条的窗口。通常,如果滚动范围太小(nPage <= nMax
),Windows会自动使这些滚动条不可见。
如果由于滚动范围太小,窗口当前处于滚动条不可见的状态,并且带有SIF_DISABLENOSCROLL
标志的SetScrollInfo
用于强制滚动条可见但被禁用,则该调用似乎没有任何效果。
如果SIF_DISABLENOSCROLL
是在滚动条当前可见时设置的(由于滚动范围足够大),则其工作正常。
这里有一个简单的切换来演示这个问题:
SCROLLINFO ScrollInfo = {};
ScrollInfo.cbSize = sizeof(ScrollInfo);
if (WantScrollBarsVisible)
{
ScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
ScrollInfo.nPage = 100;
ScrollInfo.nMax = 1; // Smaller value than nPage, so that the scroll bars should be disabled
// NOTE: If nMax is bigger than nPage, the scroll bars do become visible as expected.
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
// Bugged!! Scroll bars are still invisible.
// They *happen* to become visible as soon as the window is being resized.
}
else
{
ScrollInfo.fMask = SIF_PAGE | SIF_RANGE;
// This makes the scroll bars effectively invisible (nMin == nMax == nPage == 0)
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}
在SetScrollInfo
之后调用ShowScrollBar(..., true)
也不起作用。InvalidateRect
和UpdateWindow
也不一样。
有趣的是,也没有WM_SIZE
消息,正如您通常在SetScrollInfo
调用后所期望的那样,因为如果滚动条出现(或消失),客户端区域就会缩小。
这似乎是Windows中的一个错误。
https://microsoft.public.vc.mfc.narkive.com/7gXZ62cm/sif-disablenoscroll
事实证明,如果滚动条当前不可见,无论出于何种原因(1),将SetScrollInfo
与SIF_DISABLENOSCROLL
一起使用将永远不会使其可见。
它最初工作的原因是,在创建窗口时,滚动条碰巧有一些默认值,使其可见。如果滚动条错误地不可见,则调整窗口大小也会使滚动条可见。可能是系统更新了一堆滚动参数,然后突然意识到滚动条应该是可见的。
上面的文章包含一个解决方法:在将SetScrollInfo
与SIF_DISABLENOSCROLL
一起使用之前,首先设置一些滚动参数(使用SetScrollInfo
和而不使用SIF_DISABLENOSCROLL
),肯定会显示滚动条。每次您认为滚动条当前可能不可见时,都需要执行。
我觉得这很尴尬,于是想出了这个:
SCROLLINFO ScrollInfo = {};
ScrollInfo.cbSize = sizeof(ScrollInfo);
if (WantScrollBarsVisible)
{
// ======================================================================
// Use ShowScrollBar to ensure that the scroll bars are visible *BEFORE*
// calling SetScrollInfo with SIF_DISABLENOSCROLL.
ShowScrollBar(hWnd, SB_VERT, true);
ShowScrollBar(hWnd, SB_HORZ, true);
// ======================================================================
ScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
ScrollInfo.nPage = 100;
ScrollInfo.nMax = 1; // Smaller value than nPage, so that the scroll bars should be disabled
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}
else
{
ScrollInfo.fMask = SIF_PAGE | SIF_RANGE;
// This makes the scroll bars effectively invisible (nMin == nMax == nPage == 0)
SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}
通常,ShowScrollBar
不是很有用,因为它的效果是不稳定的——每当使用SetScrollInfo
更改滚动参数时,它们就会被覆盖。然而,在这种情况下,只要确保在SIF_DISABLENOSCROLL
出现之前滚动条是可见的就足够了。
如果可以直接与滚动条交互,甚至可能有更好的方法(比如告诉他们现在就更新自己)。
(1)我测试的可能原因包括:窗口样式WS_VSCROLL
/WS_HSCROLL
在创建后从窗口中删除;先前的nMax-nMin<=nPage
(滚动范围太小)而没有SIF_DISABLENOSCROLL
;CCD_ 26