CScrollView прокручивает только части большой площади

Я столкнулся с проблемой прокрутки больших областей в 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, чтобы полностью прокрутить большую область?

Код примера проекта можно найти Вот.

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, Это из-за 16-битных ограничений в Windows. Все элементы управления, чья позиция 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();
}

Это не решит проблему с элементами управления windows, чья позиция x / y больше 32000, но, по крайней мере, будет прокручивать DC, как и ожидалось.

Для тестирования удалите статические элементы управления. Вы можете использовать функцию рисования ниже, чтобы проверить картину:

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);
}
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]