2014-12-19 1 views
0

Я реализовал своего рода «многострочный список», создавая массив многострочных редакторов, которые касаются друг друга и могут быть прокручены.
Это прекрасно работает, пока я делаю это в главном окне. Но по определенным причинам мне нужно сделать это в окне «Дети» главного окна, и здесь у меня проблемы при прокрутке вниз (уродливый остаток предыдущей страницы остается там) и обратно в начало (та же проблема). Вертикальная прокрутка многострочного «списка» в дочернем окне создает проблемы внизу и сверху

Что я делаю неправильно?

Код:
а) 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; 
 
}

+0

Вы можете написать снимок экрана, чтобы проиллюстрировать эту проблему? –

+0

Может быть, вы можете посмотреть здесь https://www.dropbox.com/sh/w56l81muubilldp/AABvVr9p7hNAa4l6FnnadSeQa?dl=0 – Alfred

+0

Если вы видите фотографии, в нижней части экрана должно быть указано «Вставка 29» и серая полоска и вверху «Вставка 0» и серая полоска, но здесь серые полосы накладываются старым содержимым экрана (только в том случае, когда я прокручиваю в дочернем окне). – Alfred

ответ

0

Вот мое решение:

if ((pos == maxPos) || (pos == minPos)) InvalidateRect (hWnd, NULL, TRUE);

+0

Может кто-нибудь может сказать мне, почему это необходимо только при прокрутке в дочернем окне hChild, но не тогда, когда я прокручиваю в главном окне hWnd напрямую? – Alfred