尽管 SIF_DISABLENOSCROLL 滚动条不可见 [英] Scroll bar doesn't become visible despite SIF_DISABLENOSCROLL

查看:67
本文介绍了尽管 SIF_DISABLENOSCROLL 滚动条不可见的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一个窗口,它的模式我们从不希望默认 WS_HSCROLL 和/或 WS_VSCROLL 滚动条可见,而另一种模式我们总是 希望它们可见.通常,如果滚动范围太小(这样滚动实际上不可能),Windows 会自动使这些滚动条不可见.SIF_DISABLENOSCROLL 标志用于强制它们可见但禁用(而不是不可见)如果滚动参数会使滚动条无用.

Consider a window that has a mode where we never want the default WS_HSCROLL and/or WS_VSCROLL scroll bars to be visible, and another mode where we always want them to be visible. Normally, Windows automatically makes these scroll bars invisible if the scroll range it too small (such that scrolling is not actually possible). The SIF_DISABLENOSCROLL flag is used to force them to be visible but disabled (rather than being invisible) if the scroll parameters would render the scroll bar useless.

当窗口最初创建并以始终可见模式显示时,它可以工作.但是,当从始终隐藏模式切换到始终可见模式时,尽管设置了 SIF_DISABLENOSCROLL,但滚动条不会变得可见.

When the window is initially created and displayed in the always visible mode, it works. However, when switching from the always hidden mode to the always visible mode, the scroll bar does not become visible, despite SIF_DISABLENOSCROLL being set.

有一个简单的切换来演示问题:

Have a simple toggle to demonstrate the issue:

SCROLLINFO ScrollInfo = {};
ScrollInfo.cbSize = sizeof(ScrollInfo);
if (WantScrollBarsVisible)
{
    SIZE ClientSize = GetClientSize(hWnd);
    ScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
    ScrollInfo.nPage = ClientSize.cy;
    ScrollInfo.nMax = SomeHeightGreaterThan0;
    SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
    ScrollInfo.nPage = ClientSize.cx;
    ScrollInfo.nMax = SomeWidthGreaterThan0;
    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 == 0)
    SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
    SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}

SetScrollInfo 之后调用 ShowScrollBar(..., true) 也不起作用.InvalidateRectUpdateWindow 也没有.

Calling ShowScrollBar(..., true) after SetScrollInfo doesn't work either. Neither does InvalidateRect or UpdateWindow.

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

Interestingly, there is no WM_SIZE message either, as you would normally expect after a SetScrollInfo call because the client area shrinks if scroll bars appear (or disappear).

推荐答案

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

It appears to be a bug in Windows.

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

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

As it turns out, if a scroll bar is currently not visible for whatever reason(1), using SetScrollInfo with SIF_DISABLENOSCROLL will never make it visible.

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

The reason why it works initially is because upon window creation, the scroll bars happen to have some default values that will make it visible. Resizing the window also happens to make the scroll bars visible if they erroneously weren't. Probably part of the system updating a bunch of scroll parameters and then suddenly realising that the scroll bars should be visible after all.

上面的文章包含一个解决方法:在使用 SetScrollInfoSIF_DISABLENOSCROLL 之前,首先设置一些滚动参数(使用 SetScrollInfo SIF_DISABLENOSCROLL) 肯定导致滚动条显示.您每次认为滚动条可能当前不可见时都需要这样做.

The article above contains a workaround: Before using SetScrollInfo with SIF_DISABLENOSCROLL, first set some scroll parameters (with SetScrollInfo and without SIF_DISABLENOSCROLL) that definitely cause the scroll bar to be shown. You need to do that every time you think that the scroll bars might currently not be visible.

我觉得这很尴尬并想出了这个:

I found that rather awkward and came up with this:

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);
    // ======================================================================

    SIZE ClientSize = GetClientSize(hWnd);
    ScrollInfo.fMask = SIF_DISABLENOSCROLL | SIF_PAGE | SIF_RANGE;
    ScrollInfo.nPage = ClientSize.cy;
    ScrollInfo.nMax = SomeHeightGreaterThan0;
    SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
    ScrollInfo.nPage = ClientSize.cx;
    ScrollInfo.nMax = SomeWidthGreaterThan0;
    SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}
else
{
    ScrollInfo.fMask = SIF_PAGE | SIF_RANGE;
    // This makes the scroll bars effectively invisible (nMin == nMax == 0)
    SetScrollInfo(hWnd, SB_VERT, &ScrollInfo, true);
    SetScrollInfo(hWnd, SB_HORZ, &ScrollInfo, true);
}

通常,ShowScrollBar 不是很有用,因为它的效果是不稳定的 - 当使用 SetScrollInfo 更改滚动参数时,它们会被覆盖.但是,在这种情况下,在 SIF_DISABLENOSCROLL 出现之前确保滚动条可见就足够了.

Normally, ShowScrollBar is not very useful because its effects are volatile - they get overridden whenever the scroll parameters change using SetScrollInfo. However, in this case, it's just enough to make sure the scroll bars are visible before SIF_DISABLENOSCROLL comes around.

如果可以直接与滚动条进行交互,甚至可能有更好的方法(例如告诉他们立即更新自己).

If it was possible to directly interact with the scroll bars, there might even be a nicer way (like telling them to update themselves right now).

(1) 我测试过的可能原因包括: 窗口样式 WS_VSCROLL/WS_HSCROLL 在创建后从窗口中删除;以前nMax-nMin<=nPage(滚动范围太小)没有SIF_DISABLENOSCROLLShowScrollBar(..., false).

(1) The possible reasons I have tested include: Window styles WS_VSCROLL/WS_HSCROLL being removed from the window after creation; previously nMax-nMin<=nPage (scroll range too small) without SIF_DISABLENOSCROLL; ShowScrollBar(..., false).

这篇关于尽管 SIF_DISABLENOSCROLL 滚动条不可见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆