c语言 - 尽管有SIF_DISABLENOSCROLL,滚动条仍然不可见



考虑一个带有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)也不起作用。InvalidateRectUpdateWindow也不一样。

有趣的是,也没有WM_SIZE消息,正如您通常在SetScrollInfo调用后所期望的那样,因为如果滚动条出现(或消失),客户端区域就会缩小。

这似乎是Windows中的一个错误。

https://microsoft.public.vc.mfc.narkive.com/7gXZ62cm/sif-disablenoscroll

事实证明,如果滚动条当前不可见,无论出于何种原因(1),将SetScrollInfoSIF_DISABLENOSCROLL一起使用将永远不会使其可见。

它最初工作的原因是,在创建窗口时,滚动条碰巧有一些默认值,使其可见。如果滚动条错误地不可见,则调整窗口大小也会使滚动条可见。可能是系统更新了一堆滚动参数,然后突然意识到滚动条应该是可见的。

上面的文章包含一个解决方法:在将SetScrollInfoSIF_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

最新更新