locked
winapi - SetWindowPos and flickering RRS feed

  • Question

  • I have a dialog window which contains two lists view which can be resized horizontally using splitter:

    IDD_TESTBOX DIALOGEX 0, 0, 590, 300
    STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
    CAPTION "TestWinApi"
    FONT 8, "MS Shell Dlg"
    BEGIN
        CONTROL "List1",IDC_LIST1,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | WS_BORDER | WS_TABSTOP,10,10,280,280
        CONTROL "", IDC_SPLITTER, "Static", SS_BLACKFRAME, 292,10,6,280
        CONTROL "List2",IDC_LIST2,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | WS_BORDER | WS_TABSTOP,300,10,280,280
    END

    Here is the relevant part of the code:

    RECT WinRectToClientSpace(HWND dlgHwnd, HWND ctrlHwnd)
    {
        RECT r;
        GetWindowRect(ctrlHwnd, &r);
        ScreenToClient(dlgHwnd, (POINT*)&r);
        ScreenToClient(dlgHwnd, (POINT*)&r + 1);
        return r;
    }
    
    ///////////////////////////////////////////////////////
    
    case WM_MOUSEMOVE:
    {
        mousePos.x = LOWORD(lParam);
        mousePos.y = HIWORD(lParam);
    
        HWND ctrl = GetDlgItem(hDlg, IDC_SPLITTER);
        RECT r = WinRectToClientSpace(hDlg, ctrl);
    
        if (PtInRect(&r, mousePos))
        {
            SetCursor(LoadCursor(0, IDC_SIZEWE));
            splitterHit = true;
        }
        else
        {
            SetCursor(LoadCursor(0, IDC_ARROW));
            splitterHit = false;
        }
    
        if (splitterDrag)
        {
            const int dX = mousePos.x - initialSplitterPosX;
    
            SetWindowPos(ctrl, 0, mousePos.x, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
    
            ctrl = GetDlgItem(hDlg, IDC_LIST1);
            RECT r = WinRectToClientSpace(hDlg, ctrl);
            SetWindowPos(ctrl, 0, 0, 0, initialList1Width + dX, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER);
    
            ctrl = GetDlgItem(hDlg, IDC_LIST2);
            r = WinRectToClientSpace(hDlg, ctrl);
            SetWindowPos(ctrl, 0, initialList2Pos + dX, r.top, initialList2Width - dX, r.bottom - r.top, SWP_NOZORDER);
    
            GetClientRect(hDlg, &r);
            InvalidateRect(hDlg, &r, TRUE);
        }
        break;
    }
    case WM_LBUTTONDOWN:
    {
        if (splitterHit)
        {
            splitterDrag = true;
            SetCapture(hDlg);
        }
        break;
    }
    case WM_LBUTTONUP:
    {
        splitterDrag = false;
        ReleaseCapture();
        break;
    }

    As you can see InvalidateRect is called for the dialog window but I get flickering during resizing lists view. I have no idea what may be wrong. How to fix it ?

    When I add WS_CLIPCHILDREN style (dialog window) there is no flickering but the background in not repainted correctly, there remains some artifacts around the splitter.


    • Edited by Irbis88 Monday, February 10, 2020 3:27 PM
    Monday, February 10, 2020 12:04 PM

All replies

  • You can significantly reduce flickering by adding the LVS_EX_DOUBLEBUFFER extended style to the list views and by using BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos.  For example -

    if (splitterDrag)
    {
    	HDWP hdwp = BeginDeferWindowPos(3);
    	int dX = mousePos.x - initialSplitterPosX;
    
    	DeferWindowPos(hdwp, hSplitter, 0, mousePos.x, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
    
    	RECT r = WinRectToClientSpace(hWnd, hList1);
    	DeferWindowPos(hdwp, hList1, 0, 0, 0, initialList1Width + dX, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
    
    	r = WinRectToClientSpace(hWnd, hList2);
    	DeferWindowPos(hdwp, hList2, 0, initialList2Pos + dX, r.top, initialList2Width - dX, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
    
    	EndDeferWindowPos(hdwp);
    
    	//GetClientRect(hWnd, &r);
    	//InvalidateRect(hWnd, &r, TRUE);
    }
    break;
    

    Monday, February 10, 2020 2:45 PM
  • What about other controls like LTEXT, PUSHBUTTON or float_wndclass ? Should  I use WS_EX_COMPOSITED style for double buffering ?

    When a window is resized I get WM_SIZE message. Then I also use SetWindowPos to update lists view and splitter geometry but interestingly flickering doesn't occur. How to explain it ?




    • Edited by Irbis88 Monday, February 10, 2020 4:40 PM
    Monday, February 10, 2020 3:27 PM
  • Hi lrbis88,

    When you comment InvalidateRect(hDlg, &r, TRUE), can the dialog window be redrawed sucessfully?

    In addition, do you mind sharing the WM_PAINT message?

    Best regards,

    Strive


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, February 11, 2020 9:15 AM
  • A way to remove all flickering is with a GridSplitter (ElementHost to embed it in a C++/Win32 app) :

    Tuesday, February 11, 2020 1:51 PM