【问题标题】:CScrollView only scrolls through parts of a large areaCScrollView 只滚动大区域的一部分
【发布时间】:2016-07-07 09:08:49
【问题描述】:

我在 CScrollView 中滚动大面积区域时遇到问题。当从上到下缓慢移动滚动条时,行为如下:起初滚动工作正常。在某些时候,进一步滚动不会做任何事情,而是显示该区域的顶部。在某些时候,滚动会再次从顶部开始。

这是一个小例子。我使用文档视图模型创建了一个新的 MFC 项目,并使用 CScrollView 作为视图类。我添加了以下代码来创建一个大区域并添加一些文本来显示,当前显示的是哪个部分:

void CScrollViewTest2View::OnInitialUpdate()
{
    CScrollView::OnInitialUpdate();

    CSize sizeTotal;
    // TODO: calculate the total size of this view
    sizeTotal.cx = sizeTotal.cy = 100*1000;
    SetScrollSizes(MM_TEXT, sizeTotal);

    for(int i = 0; i < 1000; i++)
    {
        CStatic* label = new CStatic();
        label->Create(NULL, WS_CHILD | WS_VISIBLE, CRect(10,10 + i*100,100,30 + i*100), this);
        CString text;
        text.Format(L"%d",i);
        label->SetWindowText(text);
    }
}

如果我添加以下代码,我会看到在滚动过程中“nPos”值似乎环绕。这可以解释这种行为。但我不知道如何解决这个问题。

BOOL CScrollViewTest2View::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll )
{
    CString msg;
    msg.Format(L"nPos = %u\n",nPos);
    TRACE(msg);
    return CScrollView::OnScroll(nScrollCode, nPos, bDoScroll);
}

这是停止滚动时的输出:

nPos = 27826
nPos = 29190
nPos = 30281
nPos = 31372
nPos = 31645
nPos = 32464
nPos = 4294938588
nPos = 4294939134
nPos = 4294939407
nPos = 4294939680
nPos = 4294940225
nPos = 4294940771

那么有没有办法使用 CScrollView 完全向下滚动一大片区域呢?

示例项目的代码可以在here找到。

【问题讨论】:

  • CScrollView 使用 SetScrollRange 和其他有 16 位限制的旧函数,它只能上升到 32767‬。它应该使用SetScrollInfo/GetScrollInfo,但他们懒得更新。您在创建坐标超出 16 位范围的静态控件时还有一个问题,我认为没有解决方案。
  • 所以如果我使用'SetScrollInfo/GetScrollInfo' 编写我自己的'CScrollView' 版本,我会解决这个问题吗?你知道是否有人已经这样做并提供了它吗?静态控制和坐标超出 16 位范围究竟有什么问题?感谢您的帮助。
  • 我认为无法将窗口控件放置在 32767 范围之外。我为CScrollView 添加了一个修复程序,它用于常规绘图,否则您可能需要考虑 HTML 对话框或其他解决方案。

标签: c++ windows mfc ccscrollview


【解决方案1】:

静态控件未放置在您期望的位置。要查看问题,请运行以下代码:

static CStatic test;
CRect r(0, 0, 100, 30);
r.MoveToY(40000);
test.Create(0, WS_CHILD | WS_VISIBLE, r, this);

test.GetWindowRect(r);

TRACE("%d\n", r.top);

r.top 应该是32767。这是因为 Windows 中的 16 位限制。 x/y 位置超过此限制的所有控件都被推回此位置。

OnScroll 函数也有类似的问题,不过这可以通过使用GetScrollInfo 来解决

ON_WM_VSCROLL 添加到消息映射中,并将以下OnVScroll 覆盖到您的类中

void CScrollViewTest2View::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    CView::OnVScroll(nSBCode, nPos, pScrollBar);
    SCROLLINFO info;
    GetScrollInfo(SB_VERT, &info, SIF_ALL);

    int pos = info.nPos;
    int save = pos;
    switch (nSBCode)
    {
    case SB_LEFT: pos = info.nMin; break;
    case SB_RIGHT: pos = info.nMax; break;
    case SB_LINELEFT: pos--; break;
    case SB_LINERIGHT: pos++;  break;
    case SB_PAGELEFT: pos -= info.nPage; break;
    case SB_PAGERIGHT: pos += info.nPage; break;
    case SB_THUMBPOSITION: pos = info.nTrackPos; break;
    case SB_THUMBTRACK: pos = info.nTrackPos; break;
    }

    //make sure the new position is within range
    if (pos < info.nMin) pos = info.nMin;
    int max = info.nMax - info.nPage + 1;
    if (pos > max) pos = max;

    OnScrollBy(CSize(0, pos - save), 1);

    //EDIT: moved this line after OnScrollBy and added condition
    if (info.nPos != pos)
    {
        info.nPos = pos;
        SetScrollInfo(SB_VERT, &info, FALSE);
    }
    UpdateWindow();
} 

这不会解决 x/y 位置大于 32,000 的 windows 控件的问题,但至少它会按预期滚动 DC。

为了进行测试,请移除静态控件。您可以使用下面的draw函数来测试绘画:

void CScrollViewTest2View::OnInitialUpdate()
{
    CScrollView::OnInitialUpdate();
    CSize sizeTotal(0, 100 * 1000);
    SetScrollSizes(MM_TEXT, sizeTotal);
}

void CScrollViewTest2View::OnDraw(CDC* pDC)
{
    for (int i = 0; i < 1000; i++)
    {
        int y = i * 100;
        CString s;
        s.Format(L"%d                ", y);
        pDC->TextOutW(200, y, s);
    }
}

【讨论】:

  • 我必须切换OnScrollBySetScrollInfo 的顺序才能使其正常工作。否则,松开鼠标按钮后,拇指总是会移动一点。显然OnScrollBy 以某种方式改变了SCROLLINFO?这是正确的修复方法还是我这样做时会破坏其他东西?
  • 绝对没有办法让CStatic 以某种方式工作?在我的真实项目中,我绘制的不仅仅是数字,转换所有内容(并且很可能引入新的错误)将是一些工作。我希望其他人也遇到这个限制并以某种通用方式解决它?
  • 调整窗口大小时,它会发送WM_SIZE 消息。宽度和高度存储在 32 位 lParam 中。低 16 位是宽度,高 16 位是高度。我认为没有办法超越这些限制。您应该使用不同的方法来按需显示/隐藏窗口控件。您应该能够将控件创建为单独的窗口,以便它们出现在正确的滚动位置。然后在滚动主客户端时隐藏控件。或者尽可能使用 HTML 控件。
猜你喜欢
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 2017-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
相关资源
最近更新 更多