question

Default-1573 avatar image
0 Votes"
Default-1573 asked XiaopoYang-MSFT answered

Win32 Window resize bounce\shake

This will be the last post I make on the Tab Control. When I have a child window of a tab control and move the splitter, the bottom of the child window jitters\shakes. I have tried everything to get rid of this and nothing works. The tab control is double buffered and so is the child window of the tab control. The tab control itself is fine, it is only the child window of the tab control that is having this problem. Can someone help me fix this please?

129416-resize.gif



 #include <Windows.h>
 #include <commctrl.h>
 #include <windowsx.h>
 #include <process.h>
 #include <iostream>
 #include <Uxtheme.h>
    
 struct _WINDOW_HANDLES
 {
     HWND MainWindow;
     HWND ListViewWindow;
     HWND SplitterWindow;
    
     HWND TabMainWindow;
     HWND TabChildWindow;
    
 } wh;
    
 HINSTANCE ghInst;
    
 LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
 LRESULT CALLBACK SplitterProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
 LRESULT CALLBACK TabMainProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
 LRESULT CALLBACK TabChildWindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
 static WNDPROC SplitterWndProc;
    
 static WNDPROC TabMainWndProc;
 static WNDPROC TabChildWndProc;
    
 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow)
 {
     WNDCLASSW wc;
     memset(&wc, 0, sizeof(WNDCLASSW));
     wc.hbrBackground = NULL;
     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
     wc.hInstance = hInst;
     wc.lpszClassName = L"MainWindowClass";
     wc.lpfnWndProc = WindowProcedure;
    
     if (!RegisterClassW(&wc))
     {
         return -1;
     }
    
     wh.MainWindow = CreateWindowExW(NULL, L"MainWindowClass", L"GUI", WS_OVERLAPPEDWINDOW | WS_EX_COMPOSITED, CW_USEDEFAULT, CW_USEDEFAULT, 1300, 700, NULL, NULL, hInst, NULL);
     ShowWindow(wh.MainWindow, ncmdshow);
    
     MSG msg;
     memset(&msg, 0, sizeof(MSG));
    
     while (GetMessageW((&msg), NULL, NULL, NULL))
     {
         TranslateMessage(&msg);
         DispatchMessageW(&msg);
     }
    
     return 0;
 }
    
    
 VOID InitializeComponent(HWND hWnd)
 {
     RECT rcMain;
     GetClientRect(hWnd, &rcMain);
    
     wh.ListViewWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, rcMain.right, 265, hWnd, (HMENU)0, ghInst, NULL);
     ListView_SetExtendedListViewStyle(wh.ListViewWindow, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
    
     SendMessage(wh.ListViewWindow, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);
    
     LVCOLUMN lvc;
     memset(&lvc, 0, sizeof(LVCOLUMN));
     lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
     lvc.iSubItem = 0;
     lvc.cx = 125;
     lvc.pszText = (LPWSTR)L"Column 1";
     ListView_InsertColumn(wh.ListViewWindow, 0, &lvc);
    
     lvc.iSubItem = 1;
     lvc.cx = 125;
     lvc.pszText = (LPWSTR)L"Column 2";
     ListView_InsertColumn(wh.ListViewWindow, 1, &lvc);
    
     LVITEM lvi;
     memset(&lvi, 0, sizeof(LVITEM));
     lvi.mask = LVIF_TEXT;
     lvi.iItem = 0;
     lvi.iSubItem = 0;
     lvi.iImage = 0;
     lvi.pszText = (LPWSTR)L"Item 1";
     ListView_InsertItem(wh.ListViewWindow, &lvi);
    
     ListView_SetItemText(wh.ListViewWindow, 0, 1, (LPWSTR)L"Item 2");    
    
     wh.SplitterWindow = CreateWindowEx(NULL, WC_STATIC, L"", WS_CHILD | WS_BORDER | WS_VISIBLE | SS_NOTIFY | SS_CENTER, 0, 265, rcMain.right, 17, hWnd, NULL, ghInst, NULL);
     SplitterWndProc = (WNDPROC)SetWindowLongPtr(wh.SplitterWindow, GWLP_WNDPROC, (LONG_PTR)SplitterProcedure);
    
     LOGFONT lf;
     GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
     HFONT GeneralFont = CreateFont(
         19, 0,
         lf.lfEscapement, lf.lfOrientation, lf.lfWeight,
         lf.lfItalic, lf.lfUnderline, lf.lfStrikeOut,
         lf.lfCharSet, lf.lfOutPrecision, lf.lfClipPrecision,
         lf.lfQuality, lf.lfPitchAndFamily, NULL);
    
     wh.TabMainWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TABCONTROL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, rcMain.left, 283, rcMain.right, 378, hWnd, NULL, ghInst, NULL);
     TabMainWndProc = (WNDPROC)SetWindowLongPtr(wh.TabMainWindow, GWLP_WNDPROC, (LONG_PTR)TabMainProcedure);
     SendMessage(wh.TabMainWindow, WM_SETFONT, (WPARAM)GeneralFont, TRUE);
    
     TCITEM tie;
     tie.mask = TCIF_TEXT;
     tie.iImage = 0;
     tie.pszText = (LPWSTR)L"Tab";
     TabCtrl_InsertItem(wh.TabMainWindow, 0, &tie);
    
     wh.TabChildWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, L"", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, rcMain.left, 25, rcMain.right, 348, wh.TabMainWindow, NULL, ghInst, NULL);
     TabChildWndProc = (WNDPROC)SetWindowLongPtr(wh.TabChildWindow, GWLP_WNDPROC, (LONG_PTR)TabChildWindowProcedure);
     SendMessage(wh.TabChildWindow, WM_SETFONT, (WPARAM)GeneralFont, TRUE);
 }
    
 LRESULT CALLBACK SplitterProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static BOOL bSplitterMoving;
    
     RECT rcMain;
     GetClientRect(wh.MainWindow, &rcMain);
    
     switch (message)
     {
         case WM_SETCURSOR:
         {
             SetCursor(LoadCursor(NULL, IDC_SIZENS));
             SetWindowLongPtr(hWnd, DWLP_MSGRESULT, TRUE);
             return TRUE;
         }
    
         case WM_LBUTTONDOWN:
         {
             bSplitterMoving = TRUE;
             SetCapture(wh.SplitterWindow);
             return 0;
         }
    
         case WM_LBUTTONUP:
         {
             ReleaseCapture();
             bSplitterMoving = FALSE;
             return 0;
         }
    
         case WM_MOUSEMOVE:
         {
             if (bSplitterMoving)
             {
                 POINT  pt{ GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam) };
                 ClientToScreen(wh.SplitterWindow, &pt);
                 ScreenToClient(wh.MainWindow, &pt);
    
                 auto newSplitterPos = pt.y;
                 if (newSplitterPos <= 105 || newSplitterPos >= 265)
                 {
                     return 0;
                 }
    
                 else
                 {
                     HDWP hdwp = BeginDeferWindowPos(3);
    
                     DeferWindowPos(hdwp, wh.ListViewWindow, NULL, rcMain.left, rcMain.left, rcMain.right, newSplitterPos, NULL);
                     DeferWindowPos(hdwp, wh.SplitterWindow, NULL, rcMain.left, newSplitterPos, rcMain.right, 17, NULL);
                     DeferWindowPos(hdwp, wh.TabMainWindow, NULL, rcMain.left, newSplitterPos + 18, rcMain.right, rcMain.bottom - (newSplitterPos + 18), NULL);
                     EndDeferWindowPos(hdwp);
    
                     MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (newSplitterPos + 48), TRUE);
    
                     UpdateWindow(wh.ListViewWindow);
                     UpdateWindow(wh.SplitterWindow);
                     UpdateWindow(wh.TabMainWindow);
                 }
                 return 0;
             }
         }
     }
     return CallWindowProc(SplitterWndProc, hWnd, message, wParam, lParam);
 }
    
 LRESULT CALLBACK TabMainProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     switch (message)
     {
         PAINTSTRUCT ps;
         RECT rc;
         HDC hdc, hdcMem;
         HBITMAP hbmMem, hbmOld;
    
         case WM_PAINT:
         {
             hdc = BeginPaint(hWnd, &ps);
             GetClientRect(hWnd, &rc);
             hdcMem = CreateCompatibleDC(hdc);
             hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
             hbmOld = ((HBITMAP)SelectObject(hdcMem, hbmMem));
             FillRect(hdcMem, &rc, (HBRUSH)GetSysColorBrush(COLOR_3DFACE));
             CallWindowProc(TabMainWndProc, hWnd, message, ((WPARAM)hdcMem), lParam);
             BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
             SelectObject(hdcMem, hbmOld);
             DeleteObject(hbmMem);
             DeleteDC(hdcMem);
             EndPaint(hWnd, &ps);
    
             return 0;
         }
    
         case WM_ERASEBKGND:
         {
             return (LRESULT)1;
         }
    
         case WM_CTLCOLORSTATIC:
         {
        
             HDC hdcStatic = (HDC)wParam;
             SetBkColor(hdcStatic, RGB(0, 0, 0)); 
             return (LRESULT)GetStockObject(BLACK_BRUSH); 
                
         }
     }
    
     return CallWindowProc(TabMainWndProc, hWnd, message, wParam, lParam);
 }
    
 LRESULT CALLBACK TabChildWindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     switch (message)
     {
         PAINTSTRUCT ps;
         RECT rc;
         HDC hdc, hdcMem;
         HBITMAP hbmMem, hbmOld;
    
         case WM_PAINT:
         {
             hdc = BeginPaint(hWnd, &ps);
             GetClientRect(hWnd, &rc);
             hdcMem = CreateCompatibleDC(hdc);
             hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
             hbmOld = ((HBITMAP)SelectObject(hdcMem, hbmMem));
             FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
             CallWindowProc(TabChildWndProc, hWnd, message, ((WPARAM)hdcMem), lParam);
             BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
             SelectObject(hdcMem, hbmOld);
             DeleteObject(hbmMem);
             DeleteDC(hdcMem);
             EndPaint(hWnd, &ps);
    
             return 0;
         }
    
         case WM_ERASEBKGND:
         {
             return (LRESULT)1;
         }
     }
    
     return CallWindowProc(TabChildWndProc, hWnd, message, wParam, lParam);
 }
    
 LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
 {
     LPMINMAXINFO lpMMI = (LPMINMAXINFO)lp;
    
     RECT rcMain, rcListView;
     GetClientRect(hWnd, &rcMain);
     GetClientRect(wh.ListViewWindow, &rcListView);
    
     HMENU hMenu;
    
     switch (msg)
     {
         case WM_DESTROY:
         {
             PostQuitMessage(0);
             return 0;
         }
    
         case WM_CREATE:
         {
             InitializeComponent(hWnd);
             return 0;
         }
    
         case WM_ERASEBKGND:
         {
             HDC hdc = (HDC)wp;
             RECT rect;
             GetClientRect(hWnd, &rect);
             FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
             return 1;
         }
    
         case WM_GETMINMAXINFO:
         {
             lpMMI->ptMinTrackSize.x = 1300;
             lpMMI->ptMinTrackSize.y = 700;
             break;
         }
    
         case WM_SIZE:
         {
             POINT  pt{ GET_X_LPARAM(lp),GET_Y_LPARAM(lp) };
             ClientToScreen(wh.SplitterWindow, &pt);
             ScreenToClient(wh.MainWindow, &pt);
             int newSplitterPos = pt.y;
    
             HDWP hdwp = BeginDeferWindowPos(3);
             DeferWindowPos(hdwp, wh.ListViewWindow, NULL, rcMain.left, rcMain.left, rcMain.right, (newSplitterPos - rcMain.bottom) - 1, SWP_NOMOVE);
             DeferWindowPos(hdwp, wh.SplitterWindow, NULL, rcMain.left, (newSplitterPos - rcMain.bottom) - 1, rcMain.right, 17, SWP_NOMOVE);
             DeferWindowPos(hdwp, wh.TabMainWindow, NULL, rcMain.left, (newSplitterPos - rcMain.bottom) + 17, rcMain.right, rcMain.bottom - (rcListView.bottom + 22), SWP_NOMOVE);
             EndDeferWindowPos(hdwp);
    
             MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (rcListView.bottom + 52), TRUE);
            
             ListView_SetColumnWidth(wh.ListViewWindow, 1, LVSCW_AUTOSIZE_USEHEADER);
             SetWindowText(wh.SplitterWindow, L"...");
             return 0;
         }
     }
     return DefWindowProcW(hWnd, msg, wp, lp);
 }


c++windows-api-generalwindows-formswindows-api-ui
resize.gif (321.8 KiB)
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


It seems that WS_EX_COMPOSITED and DeferWindowPos are not used correctly.

The WS_EX_COMPOSITED style can be specified in the first argument of CreateWindowEx. If the program does not work well after this change, then it probably needs reconsiderations.

0 Votes 0 ·

Can you elaborate on this a little more please? Where is WS_EX_COMPOSITIED being used incorrectly and how is it used incorrectly?

0 Votes 0 ·

Since WS_EX_COMPOSITED is an extended style, then CreateWindowExW(NULL, L"MainWindowClass", L"GUI", WS_OVERLAPPEDWINDOW | WS_EX_COMPOSITED, …) does not look correct. (The style is interpreted as WS_CLIPCHILDREN). The code can be changed to CreateWindowExW(WS_EX_COMPOSITED, L"MainWindowClass", L"GUI", WS_OVERLAPPEDWINDOW, …).


0 Votes 0 ·
Show more comments

Removing WS_EX_COMPOSITED fixes the issue but when moving the splitter a white flicker happens for every single window. This is because I specified NULL for wc.hbrbackground.
This mean the WM_ERASEBKGND message is processed whenever any repainting needs to be done. In the example the WM_ERASEBKGND message is:

 case WM_ERASEBKGND:
         {
             HDC hdc = (HDC)wp;
             RECT rect;
             GetClientRect(hWnd, &rect);
             FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
             return 1;
         }

To stop the flickering I changed the WM_ERASEBKGND to:

 case WM_ERASEBKGND:
         {
             HDC hdc = (HDC)wp;
             RECT rect;
             GetClientRect(hWnd, &rect);
             FillRect(hdc, &rect, (HBRUSH)GetStockObject(NULL_BRUSH));
             return 1;
         }


The only issue with this is that the NULL_BRUSH smears. In this gif I removed the tab control to show how it smears underneath it. The null brush smearing can't be seen because the child windows are all sitting on top so it only smears the main window. Is this normal behavior when using a NULL_BRUSH?


129538-resize-2.gif


0 Votes 0 ·
resize-2.gif (154.0 KiB)
XiaopoYang-MSFT avatar image
0 Votes"
XiaopoYang-MSFT answered Default-1573 commented

When I change the 178 line, MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (newSplitterPos + 48), TRUE); , to MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom, TRUE);, the bounce\shake is disappeared.
MoveWindow reference.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

This would not work because it is making the child window go to the bottom of the Main Window. You can see how the scroll bars bottom arrow is no longer visible when this happens.

0 Votes 0 ·
Castorix31 avatar image
1 Vote"
Castorix31 answered

The "child " controls in a Tab control must not be child of the Tab control, but of the main window

I did a few changes and it seems to work correctly =>

 #include <Windows.h>
 #include <commctrl.h>
 #include <windowsx.h>
 #include <process.h>
 #include <iostream>
 #include <Uxtheme.h>
    
 struct _WINDOW_HANDLES
 {
     HWND MainWindow;
     HWND ListViewWindow;
     HWND SplitterWindow;
    
     HWND TabMainWindow;
     HWND TabChildWindow;
    
 } wh;
    
 HINSTANCE ghInst;
    
 LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
 LRESULT CALLBACK SplitterProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
 LRESULT CALLBACK TabMainProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
 LRESULT CALLBACK TabChildWindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
 static WNDPROC SplitterWndProc;
    
 static WNDPROC TabMainWndProc;
 static WNDPROC TabChildWndProc;
    
 int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR args, int ncmdshow)
 {
     WNDCLASSW wc;
     memset(&wc, 0, sizeof(WNDCLASSW));
     wc.hbrBackground = NULL;
     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
     wc.hInstance = hInst;
     wc.lpszClassName = L"MainWindowClass";
     wc.lpfnWndProc = WindowProcedure;
    
     if (!RegisterClassW(&wc))
     {
         return -1;
     }
    
     //wh.MainWindow = CreateWindowExW(WS_EX_COMPOSITED, L"MainWindowClass", L"GUI", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1300, 700, NULL, NULL, hInst, NULL);
     wh.MainWindow = CreateWindowExW(0, L"MainWindowClass", L"GUI", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 1300, 700, NULL, NULL, hInst, NULL);
     ShowWindow(wh.MainWindow, ncmdshow);
    
     MSG msg;
     memset(&msg, 0, sizeof(MSG));
    
     while (GetMessageW((&msg), NULL, NULL, NULL))
     {
         TranslateMessage(&msg);
         DispatchMessageW(&msg);
     }
    
     return 0;
 }
    
 VOID InitializeComponent(HWND hWnd)
 {
     RECT rcMain;
     GetClientRect(hWnd, &rcMain);
    
     wh.ListViewWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT, 0, 0, rcMain.right, 265, hWnd, (HMENU)0, ghInst, NULL);
     ListView_SetExtendedListViewStyle(wh.ListViewWindow, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
    
     SendMessage(wh.ListViewWindow, WM_CHANGEUISTATE, MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);
    
     LVCOLUMN lvc;
     memset(&lvc, 0, sizeof(LVCOLUMN));
     lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
     lvc.iSubItem = 0;
     lvc.cx = 125;
     lvc.pszText = (LPWSTR)L"Column 1";
     ListView_InsertColumn(wh.ListViewWindow, 0, &lvc);
    
     lvc.iSubItem = 1;
     lvc.cx = 125;
     lvc.pszText = (LPWSTR)L"Column 2";
     ListView_InsertColumn(wh.ListViewWindow, 1, &lvc);
    
     LVITEM lvi;
     memset(&lvi, 0, sizeof(LVITEM));
     lvi.mask = LVIF_TEXT;
     lvi.iItem = 0;
     lvi.iSubItem = 0;
     lvi.iImage = 0;
     lvi.pszText = (LPWSTR)L"Item 1";
     ListView_InsertItem(wh.ListViewWindow, &lvi);
    
     ListView_SetItemText(wh.ListViewWindow, 0, 1, (LPWSTR)L"Item 2");
    
     wh.SplitterWindow = CreateWindowEx(NULL, WC_STATIC, L"", WS_CHILD | WS_BORDER | WS_VISIBLE | SS_NOTIFY | SS_CENTER, 0, 265, rcMain.right, 17, hWnd, NULL, ghInst, NULL);
     SplitterWndProc = (WNDPROC)SetWindowLongPtr(wh.SplitterWindow, GWLP_WNDPROC, (LONG_PTR)SplitterProcedure);
    
     LOGFONT lf;
     GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
     HFONT GeneralFont = CreateFont(
         19, 0,
         lf.lfEscapement, lf.lfOrientation, lf.lfWeight,
         lf.lfItalic, lf.lfUnderline, lf.lfStrikeOut,
         lf.lfCharSet, lf.lfOutPrecision, lf.lfClipPrecision,
         lf.lfQuality, lf.lfPitchAndFamily, NULL);
    
     wh.TabMainWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TABCONTROL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, rcMain.left, 283, rcMain.right, 378, hWnd, NULL, ghInst, NULL);
     //TabMainWndProc = (WNDPROC)SetWindowLongPtr(wh.TabMainWindow, GWLP_WNDPROC, (LONG_PTR)TabMainProcedure);
     SendMessage(wh.TabMainWindow, WM_SETFONT, (WPARAM)GeneralFont, TRUE);
    
     TCITEM tie;
     tie.mask = TCIF_TEXT;
     tie.iImage = 0;
     tie.pszText = (LPWSTR)L"Tab";
     TabCtrl_InsertItem(wh.TabMainWindow, 0, &tie);
    
     //wh.TabChildWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, L"", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, rcMain.left, 25, rcMain.right, 348, wh.TabMainWindow, NULL, ghInst, NULL);
     wh.TabChildWindow = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, L"", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_WANTRETURN, rcMain.left, 25, rcMain.right, 348, hWnd, NULL, ghInst, NULL);
     //TabChildWndProc = (WNDPROC)SetWindowLongPtr(wh.TabChildWindow, GWLP_WNDPROC, (LONG_PTR)TabChildWindowProcedure);
     SendMessage(wh.TabChildWindow, WM_SETFONT, (WPARAM)GeneralFont, TRUE);
 }
    
 LRESULT CALLBACK SplitterProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     static BOOL bSplitterMoving;
    
     RECT rcMain;
     GetClientRect(wh.MainWindow, &rcMain);
    
     switch (message)
     {
     case WM_SETCURSOR:
     {
         SetCursor(LoadCursor(NULL, IDC_SIZENS));
         SetWindowLongPtr(hWnd, DWLP_MSGRESULT, TRUE);
         return TRUE;
     }
    
     case WM_LBUTTONDOWN:
     {
         bSplitterMoving = TRUE;
         SetCapture(wh.SplitterWindow);
         return 0;
     }
    
     case WM_LBUTTONUP:
     {
         ReleaseCapture();
         bSplitterMoving = FALSE;
         return 0;
     }
    
     case WM_MOUSEMOVE:
     {
         if (bSplitterMoving)
         {
             POINT  pt{ GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam) };
             ClientToScreen(wh.SplitterWindow, &pt);
             ScreenToClient(wh.MainWindow, &pt);
    
             auto newSplitterPos = pt.y;
             if (newSplitterPos <= 105 || newSplitterPos >= 265)
             {
                 return 0;
             }
    
             else
             {
                 HDWP hdwp = BeginDeferWindowPos(4);
    
                 DeferWindowPos(hdwp, wh.ListViewWindow, NULL, rcMain.left, rcMain.left, rcMain.right, newSplitterPos, NULL);
                 DeferWindowPos(hdwp, wh.SplitterWindow, NULL, rcMain.left, newSplitterPos, rcMain.right, 17, NULL);
                 DeferWindowPos(hdwp, wh.TabMainWindow, NULL, rcMain.left, newSplitterPos + 18, rcMain.right, rcMain.bottom - (newSplitterPos + 18), NULL);
                 RECT rcTab;
                 SetRect(&rcTab, rcMain.left, newSplitterPos + 18, rcMain.right, rcMain.bottom - rcMain.top);
                 TabCtrl_AdjustRect(wh.TabMainWindow, FALSE, &rcTab);
                 DeferWindowPos(hdwp,
                     wh.TabChildWindow, HWND_TOP, rcTab.left, rcTab.top,
                     rcTab.right - rcTab.left, rcTab.bottom - rcTab.top, 0
                 );
                 EndDeferWindowPos(hdwp);  
    
                 //MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (newSplitterPos + 48), TRUE);
    
                 //UpdateWindow(wh.ListViewWindow);
                 // UpdateWindow(wh.SplitterWindow);
                //  UpdateWindow(wh.TabMainWindow);
             }
             return 0;
         }
     }
     }
     return CallWindowProc(SplitterWndProc, hWnd, message, wParam, lParam);
 }
    
 LRESULT CALLBACK TabMainProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     switch (message)
     {
         PAINTSTRUCT ps;
         RECT rc;
         HDC hdc, hdcMem;
         HBITMAP hbmMem, hbmOld;
    
     case WM_PAINT:
     {
         hdc = BeginPaint(hWnd, &ps);
         GetClientRect(hWnd, &rc);
         hdcMem = CreateCompatibleDC(hdc);
         hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
         hbmOld = ((HBITMAP)SelectObject(hdcMem, hbmMem));
         FillRect(hdcMem, &rc, (HBRUSH)GetSysColorBrush(COLOR_3DFACE));
         CallWindowProc(TabMainWndProc, hWnd, message, ((WPARAM)hdcMem), lParam);
         BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
         SelectObject(hdcMem, hbmOld);
         DeleteObject(hbmMem);
         DeleteDC(hdcMem);
         EndPaint(hWnd, &ps);
    
         return 0;
     }
    
     case WM_ERASEBKGND:
     {
         return (LRESULT)1;
     }
    
     case WM_CTLCOLORSTATIC:
     {
    
         HDC hdcStatic = (HDC)wParam;
         SetBkColor(hdcStatic, RGB(0, 0, 0));
         return (LRESULT)GetStockObject(BLACK_BRUSH);
    
     }
     }
    
     return CallWindowProc(TabMainWndProc, hWnd, message, wParam, lParam);
 }
    
 LRESULT CALLBACK TabChildWindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
     switch (message)
     {
         PAINTSTRUCT ps;
         RECT rc;
         HDC hdc, hdcMem;
         HBITMAP hbmMem, hbmOld;
    
     case WM_PAINT:
     {
         hdc = BeginPaint(hWnd, &ps);
         GetClientRect(hWnd, &rc);
         hdcMem = CreateCompatibleDC(hdc);
         hbmMem = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
         hbmOld = ((HBITMAP)SelectObject(hdcMem, hbmMem));
         FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
         CallWindowProc(TabChildWndProc, hWnd, message, ((WPARAM)hdcMem), lParam);
         BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hdcMem, 0, 0, SRCCOPY);
         SelectObject(hdcMem, hbmOld);
         DeleteObject(hbmMem);
         DeleteDC(hdcMem);
         EndPaint(hWnd, &ps);
    
         return 0;
     }
    
     case WM_ERASEBKGND:
     {
         return (LRESULT)1;
     }
     }
    
     return CallWindowProc(TabChildWndProc, hWnd, message, wParam, lParam);
 }
    
 LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
 {
     int newSplitterPos = 0;
     LPMINMAXINFO lpMMI = (LPMINMAXINFO)lp;
    
     RECT rcMain, rcListView;
     GetClientRect(hWnd, &rcMain);
     GetClientRect(wh.ListViewWindow, &rcListView);
    
     HMENU hMenu;
    
     switch (msg)
     {
     case WM_DESTROY:
     {
         PostQuitMessage(0);
         return 0;
     }
     case WM_CREATE:
     {
         InitializeComponent(hWnd);
         return 0;
     }
     //case WM_ERASEBKGND:
     //{
     //    HDC hdc = (HDC)wp;
     //    RECT rect;
     //    GetClientRect(hWnd, &rect);
     //    FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
     //    return 1;
     //}
     case WM_ERASEBKGND:
     {  
         return 1;
     }
    
     case WM_GETMINMAXINFO:
     {
         lpMMI->ptMinTrackSize.x = 1300;
         lpMMI->ptMinTrackSize.y = 700;
         break;
     }
     // For Read-Only Edit control
     case WM_CTLCOLORSTATIC:
     {
         if (lp == (LPARAM)wh.TabChildWindow)
         {
             HDC hdcStatic = (HDC)wp;
             SetBkColor(hdcStatic, RGB(0, 0, 0));
             return (LRESULT)GetStockObject(BLACK_BRUSH);
         }
     }
     break;
     case WM_SIZE:
     {
         POINT  pt{ GET_X_LPARAM(lp),GET_Y_LPARAM(lp) };
         ClientToScreen(wh.SplitterWindow, &pt);
         ScreenToClient(wh.MainWindow, &pt);
         newSplitterPos = pt.y;
    
         HDWP hdwp = BeginDeferWindowPos(4);
         DeferWindowPos(hdwp, wh.ListViewWindow, NULL, rcMain.left, rcMain.left, rcMain.right, (newSplitterPos - rcMain.bottom) - 1, SWP_NOMOVE);
         DeferWindowPos(hdwp, wh.SplitterWindow, NULL, rcMain.left, (newSplitterPos - rcMain.bottom) - 1, rcMain.right, 17, SWP_NOMOVE);
         DeferWindowPos(hdwp, wh.TabMainWindow, NULL, rcMain.left, (newSplitterPos - rcMain.bottom) + 17, rcMain.right, rcMain.bottom - (rcListView.bottom + 22), SWP_NOMOVE);
         RECT rcTab;
         SetRect(&rcTab, rcMain.left, (newSplitterPos - rcMain.bottom) + 17, rcMain.right, rcMain.bottom - rcMain.top);
         TabCtrl_AdjustRect(wh.TabMainWindow, FALSE, &rcTab);
         DeferWindowPos(hdwp,
             wh.TabChildWindow, HWND_TOP, rcTab.left, rcTab.top,
             rcTab.right - rcTab.left, rcTab.bottom - rcTab.top, 0
         );
         EndDeferWindowPos(hdwp);
         //MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (rcListView.bottom + 52), TRUE);
    
         ListView_SetColumnWidth(wh.ListViewWindow, 1, LVSCW_AUTOSIZE_USEHEADER);
         SetWindowText(wh.SplitterWindow, L"...");
         return 0;
     }
     }
     return DefWindowProcW(hWnd, msg, wp, lp);
 }


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

XiaopoYang-MSFT avatar image
0 Votes"
XiaopoYang-MSFT answered

After researching, we found that using SWP_NOREDRAW when moving wh.TabMainWindow will also address the issue:

             HDWP hdwp = BeginDeferWindowPos(3);
    
             DeferWindowPos(hdwp, wh.ListViewWindow, NULL, rcMain.left, rcMain.left, rcMain.right, newSplitterPos, NULL);
             DeferWindowPos(hdwp, wh.SplitterWindow, NULL, rcMain.left, newSplitterPos, rcMain.right, 17, NULL);
             DeferWindowPos(hdwp, wh.TabMainWindow, NULL, rcMain.left, newSplitterPos + 18, rcMain.right, rcMain.bottom - (newSplitterPos + 18), SWP_NOREDRAW);
             EndDeferWindowPos(hdwp);
    
             MoveWindow(wh.TabChildWindow, rcMain.left, 25, rcMain.right, rcMain.bottom - (newSplitterPos + 48), TRUE);
    
             RedrawWindow(wh.TabMainWindow, nullptr, nullptr, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW);
             RedrawWindow(wh.MainWindow, nullptr, nullptr, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
    
             UpdateWindow(wh.ListViewWindow);
             UpdateWindow(wh.SplitterWindow);

SWP_NOREDRAW prevents the redrawing of the edit control.
RedrawWindow(wh.TabMainWindow,…) to have the tab control repaint including its non-client area. Without it, the area not drawn due to SWP_NOREDRAW will not be repainted.
RedrawWindow(wh.MainWindow,…) to have the main window repaint with WM_ERASEBKGND. Without it, the area not drawn due to SWP_NOREDRAW will not be repainted. This is not needed if the child controls completely cover the main window, but that is not the case with the code.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.