首页 > 解决方案 > 如何在按住滚动条的同时强制重绘 WIN32 滚动窗口

问题描述

在此处输入图像描述我们注意到我们的 Windows 应用程序上的 ScrollWindowEx 存在问题。因为子窗口很多,如果按住滚动条四处走动,会导致DesktopWindowManager出现巨大的卡顿。

这记录在这里

为什么我的 MFC 应用程序在与两个滚动条交互后挂起?

所以,我已经取消了对 ScrollWindowEx 的调用,现在我可以毫无问题地移动我的滚动条,但是当我放开滚动条时,窗口及其所有子项只会在新位置绘制。

按住滚动条时,我的整个程序似乎停止并卡在消息循环中。如果我们可以强制滚动条附加到的窗口更新,这不是问题。但我该怎么做呢?

我试过这个

UpdateWindow(pPane);
RedrawWindow(pPane,NULL,NULL,RDW_ALLCHILDREN|RDW_INVALIDATE|RDW_ERASE | RDW_INTERNALPAINT | RDW_UPDATENOW);

它确实会更新和重绘 - 你可以看到故障 - 但它会在上次离开的位置重绘它。不是滚动条的新位置将设置它的位置。

我打电话

SetScrollInfo(...)

参数正确,否则无法正常工作

如何在按住滚动条的同时使用正确的参数重绘窗口及其子项?

这是我的滚动消息处理程序

case WM_VSCROLL:
    {
        int iVScrollPos;
        SCROLLINFO vsi;
        ZeroMemory(&vsi, sizeof(SCROLLINFO));

        vsi.cbSize=sizeof(SCROLLINFO);
        vsi.fMask=SIF_ALL;
        GetScrollInfo(hWnd,SB_VERT,&vsi);
        iVScrollPos=vsi.nPos;

        switch(LOWORD(wParam))
        {
           case SB_LINEUP:
                if(vsi.nPos>vsi.nMin)
                   vsi.nPos=vsi.nPos-10;
                break;
           case SB_PAGEUP:
                vsi.nPos = vsi.nPos - vsi.nPage;
                break;
           case SB_LINEDOWN:
                if(vsi.nPos<vsi.nMax)
                   vsi.nPos=vsi.nPos+10;
                break;
           case SB_PAGEDOWN:
                vsi.nPos = vsi.nPos + vsi.nPage;
                break;
           case SB_THUMBTRACK:
                vsi.nPos=vsi.nTrackPos;
                break;
        }

        vsi.nMin=0;
        vsi.nMax=pOW->dialogysize;          
        vsi.nPage=sy;           

        SetScrollInfo(hWnd,SB_VERT,&vsi,TRUE);
        GetScrollInfo(hWnd, SB_VERT, &vsi);     
        
        if(vsi.nPos != iVScrollPos)
        {                 
RedrawWindow(hWnd,NULL,NULL,RDW_ALLCHILDREN|RDW_INVALIDATE|RDW_ERASE | RDW_INTERNALPAINT | RDW_UPDATENOW);
}

当您移动滚动条时,窗口会重新绘制,但在您将鼠标按住滚动条时的相同位置。它仅在您松开鼠标按钮时更新位置。

谢谢

肖恩

编辑 - 我创建了一个重现行为的示例。请注意,我们有一个单独的窗口类来保存多个编辑窗口。我没有在这个演示中处理 WM_SIZE 和 WM_MOVE 消息,但代码应该可以在窗口中正常工作。

如果在中定义了 USESCROLL 并且您上下移动滚动条,则会导致 DesktopWindowManager 中的锁定

如果未注释 USESCROLL,则结构中的 trackPos 仍会更新并且我调用 reDrawWindow,但是当我滚动滚动条时子编辑窗口不会移动。

由于我不想被锁定,请问我怎样才能让他们移动?

再次感谢

肖恩

#include <windows.h>
#include <stdio.h>

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK PaneProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
    
    WNDCLASS wc = { };

    wc.lpfnWndProc   = WindowProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = "Class";

    RegisterClass(&wc);

    wc.lpfnWndProc   = PaneProc;
    wc.hInstance     = hInstance;
    wc.lpszClassName = "Pane";

    RegisterClass(&wc);

    // Create the window.

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        (LPCSTR)"Class",                     // Window class
        (LPCSTR)"Test",    // Window text
        WS_OVERLAPPEDWINDOW| WS_BORDER | WS_CAPTION | WS_CLIPSIBLINGS | WS_THICKFRAME | WS_SYSMENU,            // Window style
        200,200,400,400,
        NULL,NULL,hInstance,NULL);
    
    if (hwnd == NULL)
    {
        return 0;
    }
      HWND hwndPane = CreateWindowEx(
        0,                              // Optional window styles.
        (LPCSTR)"Pane",                     // Window class
        (LPCSTR)"Test",    // Window text
        WS_OVERLAPPEDWINDOW|WS_VISIBLE|WS_VSCROLL,            // Window style
        220,220,400,400,
        hwnd,NULL,hInstance,NULL);
      
    if (hwndPane == NULL)
    {
        return 0;
    }

    for(int i=0;i<200;i++)
    {
        HWND eb = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("Edit"), NULL,ES_AUTOHSCROLL  | WS_CHILD| WS_VISIBLE, 16, 16+24*i, 64, 24, hwndPane, (HMENU)i+10000, hInstance, NULL);
        char tmp[64];
        sprintf(tmp,"%d",i);
        SetWindowText(eb,tmp);
    }

    ShowWindow(hwnd, nCmdShow);
    ShowWindow(hwndPane, nCmdShow);

    // Run the message loop.
    while(1)
    {
        MSG msg = { };
        
        while (PeekMessage(&msg, NULL, 0,0,PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        Sleep(10);
    }

    return 0;
}


LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hwnd, &ps);

            FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));

            EndPaint(hwnd, &ps);
        }
        return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}


LRESULT CALLBACK PaneProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {

    case WM_CREATE:

        int iVScrollPos;
        SCROLLINFO vsi;
        ZeroMemory(&vsi, sizeof(SCROLLINFO));

        vsi.cbSize=sizeof(SCROLLINFO);
        vsi.fMask=SIF_ALL;      
        GetScrollInfo(hwnd,SB_VERT,&vsi);
        iVScrollPos=vsi.nPos;

        vsi.nMin=0;
        vsi.nMax=16+24*200+40;      
        vsi.nPage=400;          

        SetScrollInfo(hwnd,SB_VERT,&vsi,TRUE);
        GetScrollInfo(hwnd, SB_VERT, &vsi);     
        break;
            
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_VSCROLL:
    {
           int iVScrollPos;
           SCROLLINFO vsi;
           ZeroMemory(&vsi, sizeof(SCROLLINFO));

           vsi.cbSize=sizeof(SCROLLINFO);
           vsi.fMask=SIF_ALL;       
           GetScrollInfo(hwnd,SB_VERT,&vsi);
           iVScrollPos=vsi.nPos;

            switch(LOWORD(wParam))
            {
               case SB_THUMBTRACK:
                    vsi.nPos=vsi.nTrackPos;
                    break;
            }

            vsi.nMin=0;
            vsi.nMax=16+24*200+40;      
            vsi.nPage=400;          

            SetScrollInfo(hwnd,SB_VERT,&vsi,TRUE);
            GetScrollInfo(hwnd, SB_VERT, &vsi);     
            
            if(vsi.nPos != iVScrollPos)
            {
                float ScrollAmtY=-(vsi.nPos - iVScrollPos);

#define USESCROLL
#ifdef USESCROLL
                int ok=ScrollWindowEx(hwnd ,0,ScrollAmtY,NULL,NULL,NULL,NULL,SW_INVALIDATE|SW_ERASE|SW_SCROLLCHILDREN);
#else
                UpdateWindow(hwnd);
                RedrawWindow(hwnd,NULL,NULL,RDW_ALLCHILDREN|RDW_INVALIDATE|RDW_ERASE | RDW_INTERNALPAINT | RDW_UPDATENOW);
#endif
            }
            return 0;
        }
        break;


    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

标签: windowswinapiscrollbar

解决方案


推荐阅读