Я реализовал своего рода «многострочный список», создавая массив многострочных редакторов, которые касаются друг друга и могут быть прокручены.
Это прекрасно работает, пока я делаю это в главном окне. Но по определенным причинам мне нужно сделать это в окне «Дети» главного окна, и здесь у меня проблемы при прокрутке вниз (уродливый остаток предыдущей страницы остается там) и обратно в начало (та же проблема). Вертикальная прокрутка многострочного «списка» в дочернем окне создает проблемы внизу и сверху
Что я делаю неправильно?
Код:а) srolling в главном окне
#include <windows.h>
#include <stdio.h>
#define ITEMS 30 /*number of items in list*/
#define HEIGHT 80 /*height of one item in pixels*/
static int curr_y=20; // current y position to add next item
static HWND hWnd; // main windo handle
static int cxClient;// width;
static int cyClient;// height
//-------------------------------------------------------
void GetClientSize(HWND hWndParent)
{
RECT rcl;
GetClientRect(hWndParent, &rcl);
cxClient = rcl.right;
cyClient = rcl.bottom;
}
//-------------------------------------------------------
void Debug(TCHAR *Fmt, ...)
{
va_list argptr;
TCHAR buf[1000];
va_start(argptr, Fmt);
vsprintf(buf, Fmt, argptr);
OutputDebugString(buf);
va_end(argptr);
}
//-------------------------------------------------------
static void VScrollClient(HWND hwnd, int pos)
{
static int prev = 0;
int cy = prev - pos;
prev = pos;
if(cy) ScrollWindow(hwnd, 0, cy, NULL, NULL);
}
//-------------------------------------------------------
static void CreateMultilineBox(HWND hwnd, int id)
{
GetClientSize(hwnd);
TCHAR buf[100];
sprintf(buf,TEXT("This is\r\nBox %d"),id);
CreateWindow(TEXT("edit"), buf,
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE ,
50, curr_y, cxClient-100, HEIGHT+1,
hwnd, (HMENU)id+100,
GetModuleHandle(NULL), NULL);
curr_y += HEIGHT;
}
//-------------------------------------------------------
static LRESULT
CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
// setup scroll info (Min,Max,Page size)
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
si.nPos = 0;
si.nMin = 0;
si.nMax = HEIGHT*ITEMS;
si.nPage = cyClient;
SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
}
break;
case WM_SIZE:
{
int cyClient = HIWORD(lParam);
// update scroll page size
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE;
si.nPage = cyClient;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
// update window if maximized.
if(wParam == SIZE_MAXIMIZED)
{
si.fMask = SIF_RANGE | SIF_POS;
GetScrollInfo(hwnd, SB_VERT, &si);
VScrollClient(hwnd, si.nPos);
}
return 0;
}
case WM_VSCROLL:
{
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
GetScrollInfo(hwnd, SB_VERT, &si);
const int minPos = si.nMin;
const int maxPos = si.nMax - (si.nPage - HEIGHT);
int pos = -1;
Debug(TEXT("\n nMax=%d nPage=%d\n minPos=%d maxPos=%d nPos=%d"),
si.nMax, si.nPage, minPos, maxPos, si.nPos);
switch(LOWORD(wParam)) //code
{
case SB_LINEUP:
pos = max(si.nPos - HEIGHT, minPos);
break;
case SB_LINEDOWN:
pos = min(si.nPos + HEIGHT, maxPos);
break;
case SB_PAGEUP:
pos = max(si.nPos - (int)si.nPage, minPos);
break;
case SB_PAGEDOWN:
pos = min(si.nPos + (int)si.nPage, maxPos);
break;
case SB_TOP:
pos = minPos;
break;
case SB_BOTTOM:
pos = maxPos;
break;
case SB_THUMBTRACK:
if(si.nTrackPos>=maxPos-HEIGHT) pos=maxPos;
else pos = (si.nTrackPos/HEIGHT)*(HEIGHT);
break;
}
if(pos == -1) return 0;
SetScrollPos(hwnd, SB_VERT, pos, TRUE);
VScrollClient(hwnd, pos);
return 0;
}
case WM_KEYDOWN:
{
switch(wParam) // character code
{
case VK_UP:
SendMessage (hwnd, WM_VSCROLL, SB_LINEUP, 0);
break;
case VK_DOWN:
SendMessage (hwnd, WM_VSCROLL, SB_LINEDOWN,0);
break;
case VK_PRIOR:
SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0);
break;
case VK_NEXT:
SendMessage (hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
break;
case VK_HOME:
SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0);
break;
case VK_END:
SendMessage (hwnd, WM_VSCROLL, SB_BOTTOM, 0);
break;
default:
return 0;
}
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
ReleaseDC(hwnd, hdc);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
//-------------------------------------------------------
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASSW wc = {0};
wc.lpszClassName = L"myclass";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0,IDC_ARROW);
RegisterClassW(&wc);
hWnd=CreateWindowW(wc.lpszClassName, L"test scrolling",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_VSCROLL,
10, 10, 900, 600, 0, 0, hInstance, 0);
if(!hWnd) return 0;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
for(int i=0;i<ITEMS;i++)
{
CreateMultilineBox(hWnd, i);
}
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
б) скроллинг в дочернем окне
#include <windows.h>
#include <stdio.h>
#define ITEMS 30 /*number of items in list*/
#define HEIGHT 80 /*height of one item in pixels*/
static int curr_y=20; // current y position to add next item
static HWND hWnd; // main windo handle
static HWND hChild;
static int cxClient;// width;
static int cyClient;// height
//-------------------------------------------------------
void GetClientSize(HWND hWndParent)
{
RECT rcl;
GetClientRect(hWndParent, &rcl);
cxClient = rcl.right;
cyClient = rcl.bottom;
}
//-------------------------------------------------------
void Debug(TCHAR *Fmt, ...)
{
va_list argptr;
TCHAR buf[1000];
va_start(argptr, Fmt);
vsprintf(buf, Fmt, argptr);
OutputDebugString(buf);
va_end(argptr);
}
//-------------------------------------------------------
static void VScrollClient(HWND hwnd, int pos)
{
static int prev = 0;
int cy = prev - pos;
prev = pos;
if(cy) ScrollWindow(hwnd, 0, cy, NULL, NULL);
}
//-------------------------------------------------------
static void CreateMultilineBox(HWND hwnd, int id)
{
GetClientSize(hwnd);
TCHAR buf[100];
sprintf(buf,TEXT("This is\r\nBox %d"),id);
CreateWindow(TEXT("edit"), buf,
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE ,
50, curr_y, cxClient-100, HEIGHT+1,
hwnd, (HMENU)id+100,
GetModuleHandle(NULL), NULL);
curr_y += HEIGHT;
}
//-------------------------------------------------------
static LRESULT
CALLBACK ChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
{
// setup scroll info (Min,Max,Page size)
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
si.nPos = 0;
si.nMin = 0;
si.nMax = HEIGHT*ITEMS;
si.nPage = cyClient;
SetScrollInfo(hwnd, SB_VERT, &si, FALSE);
}
break;
case WM_SIZE:
{
int cyClient = HIWORD(lParam);
// update scroll page size
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE;
si.nPage = cyClient;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
// update window if maximized.
if(wParam == SIZE_MAXIMIZED)
{
si.fMask = SIF_RANGE | SIF_POS;
GetScrollInfo(hwnd, SB_VERT, &si);
VScrollClient(hwnd, si.nPos);
}
return 0;
}
case WM_VSCROLL:
{
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
GetScrollInfo(hwnd, SB_VERT, &si);
const int minPos = si.nMin;
const int maxPos = si.nMax - (si.nPage - HEIGHT);
int pos = -1;
Debug(TEXT("\n nMax=%d nPage=%d\n minPos=%d maxPos=%d nPos=%d"),
si.nMax, si.nPage, minPos, maxPos, si.nPos);
switch(LOWORD(wParam)) //code
{
case SB_LINEUP:
pos = max(si.nPos - HEIGHT, minPos);
break;
case SB_LINEDOWN:
pos = min(si.nPos + HEIGHT, maxPos);
break;
case SB_PAGEUP:
pos = max(si.nPos - (int)si.nPage, minPos);
break;
case SB_PAGEDOWN:
pos = min(si.nPos + (int)si.nPage, maxPos);
break;
case SB_TOP:
pos = minPos;
break;
case SB_BOTTOM:
pos = maxPos;
break;
case SB_THUMBTRACK:
if(si.nTrackPos>=maxPos-HEIGHT) pos=maxPos;
else pos = (si.nTrackPos/HEIGHT)*(HEIGHT);
break;
}
if(pos == -1) return 0;
SetScrollPos(hwnd, SB_VERT, pos, TRUE);
VScrollClient(hwnd, pos);
return 0;
}
case WM_KEYDOWN:
{
switch(wParam) // character code
{
case VK_UP:
SendMessage (hwnd, WM_VSCROLL, SB_LINEUP, 0);
break;
case VK_DOWN:
SendMessage (hwnd, WM_VSCROLL, SB_LINEDOWN,0);
break;
case VK_PRIOR:
SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0);
break;
case VK_NEXT:
SendMessage (hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
break;
case VK_HOME:
SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0);
break;
case VK_END:
SendMessage (hwnd, WM_VSCROLL, SB_BOTTOM, 0);
break;
default:
return 0;
}
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
ReleaseDC(hwnd, hdc);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
} /* ChildProc */
//==============================================================================
static void ChildRegister(void)
{
WNDCLASS wc = { 0 };
wc.style = 0;
wc.lpfnWndProc = ChildProc;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = TEXT("Child");
RegisterClass(&wc);
}
//-------------------------------------------------------
static HWND CreateChild(HWND hwnd)
{
GetClientSize(hwnd);
HWND hChild = CreateWindow(TEXT("Child"), NULL,
WS_VISIBLE | WS_CHILD | WS_VSCROLL,
0, 0, cxClient, cyClient,
hwnd, (HMENU)0, GetModuleHandle(NULL), NULL);
if(!hChild)
{
Debug(TEXT("\r\nCreate Cont failed, error=%d"),GetLastError());
}
return hChild;
}
//------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
break;
case WM_SIZE:
{
cxClient = LOWORD (lParam) ; // width
cyClient = HIWORD (lParam) ; // heigth
MoveWindow(hChild, 0, 0, cxClient, cyClient, TRUE);
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
//-------------------------------------------------------
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASSW wc = {0};
wc.lpszClassName = L"myclass";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0,IDC_ARROW);
RegisterClassW(&wc);
hWnd=CreateWindowW(wc.lpszClassName, L"test scrolling",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10, 10, 900, 600, 0, 0, hInstance, 0);
if(!hWnd) return 0;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
ChildRegister();
hChild =CreateChild(hWnd);
if(!hChild) return 0;
SetFocus(hChild);
for(int i=0;i<ITEMS;i++)
{
CreateMultilineBox(hChild, i);
}
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
Вы можете написать снимок экрана, чтобы проиллюстрировать эту проблему? –
Может быть, вы можете посмотреть здесь https://www.dropbox.com/sh/w56l81muubilldp/AABvVr9p7hNAa4l6FnnadSeQa?dl=0 – Alfred
Если вы видите фотографии, в нижней части экрана должно быть указано «Вставка 29» и серая полоска и вверху «Вставка 0» и серая полоска, но здесь серые полосы накладываются старым содержимым экрана (только в том случае, когда я прокручиваю в дочернем окне). – Alfred