C++ 绕过WS_CLIPCHILDREN

C++ 绕过WS_CLIPCHILDREN,c++,winapi,C++,Winapi,我创建了一个带有透明度选项的自定义滚动条。这种透明度的工作方式非常简单,我使所需区域无效,让父对象擦除并绘制自己,然后重新绘制滚动条本身。下面是一些代码: void Refresh(bool bForceOwnerRedraw) { if (Gui.OwnerRedraw || bForceOwnerRedraw) InvalidateBackgroundRegion(State.CurrentState); RedrawWind

我创建了一个带有透明度选项的自定义滚动条。这种透明度的工作方式非常简单,我使所需区域无效,让父对象擦除并绘制自己,然后重新绘制滚动条本身。下面是一些代码:

void Refresh(bool bForceOwnerRedraw)
    {
        if (Gui.OwnerRedraw || bForceOwnerRedraw)
            InvalidateBackgroundRegion(State.CurrentState);

        RedrawWindow(Gui.OwnerWindow, &Gui.DrawingRectangle, NULL, RDW_INVALIDATE | RDW_NOERASE | RDW_INTERNALPAINT);
    }

void InvalidateBackgroundRegion(DWORD State)
    {
        HWND hWndParent = GetParent(Gui.OwnerWindow);
        POINT p = {0};

        MapWindowPoints(Gui.OwnerWindow, hWndParent, &p, 1);

        HRGN BackGroundRegion = CreateRectRgn(Gui.DrawingRectangle.left + p.x, Gui.DrawingRectangle.top + p.y, Gui.DrawingRectangle.right + p.x, Gui.DrawingRectangle.bottom + p.y);
        HRGN MainRegion = NULL;

        if (State & SELECTED || State & SELECTED_HOVER)
        {
            int Width = Gui.DrawingRectangle.left + Position.SelectedState.MainDrawing.right + p.x + 1,
                Height = Gui.DrawingRectangle.top + Position.SelectedState.MainDrawing.bottom + p.y + 1;

            MainRegion = CreateRoundRectRgn(Position.SelectedState.MainDrawing.left + Gui.DrawingRectangle.left + p.x, Position.SelectedState.MainDrawing.top + Gui.DrawingRectangle.top + p.y, Width, Height, Gui.uiCornerRoundness, Gui.uiCornerRoundness);
        }
        else if (State & UNSELECTED || State & UNSELECTED_HOVER)
        {
            int Width = Gui.DrawingRectangle.left + Position.UnselectedState.MainDrawing.right + p.x + 1,
                Height = Gui.DrawingRectangle.top + Position.UnselectedState.MainDrawing.bottom + p.y + 1;

            MainRegion = CreateRoundRectRgn(Position.UnselectedState.MainDrawing.left+Gui.DrawingRectangle.left+p.x, Position.UnselectedState.MainDrawing.top+Gui.DrawingRectangle.top+p.y, Width, Height, Gui.uiCornerRoundness, Gui.uiCornerRoundness);
        }
        else if (State & INTERMEDIATE || State & INTERMEDIATE_HOVER)
        {
            int Width = Gui.DrawingRectangle.left + Position.IntermediateState.MainDrawing.right + p.x + 1,
                Height = Gui.DrawingRectangle.top + Position.IntermediateState.MainDrawing.bottom + p.y + 1;

            MainRegion = CreateRoundRectRgn(Position.IntermediateState.MainDrawing.left + Gui.DrawingRectangle.left + p.x, Position.IntermediateState.MainDrawing.top + Gui.DrawingRectangle.top + p.y, Width, Height, Gui.uiCornerRoundness, Gui.uiCornerRoundness);
        }
        CombineRgn(BackGroundRegion, BackGroundRegion, MainRegion, RGN_DIFF);
        RedrawWindow(hWndParent, NULL, BackGroundRegion, RDW_INVALIDATE | RDW_ERASE | RDW_INTERNALPAINT);

        DeleteObject(MainRegion);
        DeleteObject(BackGroundRegion);
    }
当我调整主窗口的大小时,问题就出现了,所有的东西都会闪烁。然而,我可以通过在主窗口上使用
WS_CLIPCHILDREN
标志来防止这种情况,但是我的滚动条失去了它的透明度,因为我不再能够使子窗口拥有的部分无效

到目前为止,我所尝试的:

  • 在使父项无效之前,我删除了
    WS_CLIPCHILDREN
    标志,重新绘制,然后重新设置
    WS_CLIPCHILDREN
    标志。[结果:它起作用了,但是我的CPU使用率超过了30%,所以它是一个no no.]

  • 在擦除和重新绘制之前,已尝试验证子窗口(不带
    WS\u CLIPCHILDREN
    )。 [结果:不起作用,不知道为什么…也许我…不知道。]

  • 完全禁用我的滚动条中的所有重新绘制(无
    WS\u CLIPCHILDREN
    )[结果:未工作,仍闪烁。]

  • 我想在这里实现的是找到一种方法,通过手动使窗口无效来绕过WS_CLIPCHILDREN(可能以某种方式使用SendMessage()来绕过它)。我们也欢迎任何其他建议。谢谢

    编辑:

    有关如何创建滚动条的更多信息。在下面的代码中,您可以看到我的滚动条只是一个空的子窗口,带有
    WS_VISIBLE
    WS_child
    标志,所有的绘制都是使用良好的旧gdi完成的

    void RegisterScrollbarClass()
        {
            if (RegisteredClasses.bCustomScrollBar)
                return;
    
            WNDCLASSEX wc;
    
            wc.cbSize        = sizeof(WNDCLASSEX);
            wc.style         = CS_HREDRAW | CS_VREDRAW;
            wc.lpfnWndProc   = BaseWindow::stWinMsgHandler;
            wc.cbClsExtra    = 0;
            wc.cbWndExtra    = 0;
            wc.hInstance     = NULL;
            wc.hIcon         = NULL;
            wc.hCursor       = NULL;
            wc.hbrBackground = NULL;
            wc.lpszMenuName  = NULL;
            wc.lpszClassName = TEXT("CUSTOM_SCROLLBAR");
            wc.hIconSm       = NULL;
    
            if (!RegisterClassEx(&wc))
            {
                MessageBox(NULL, TEXT("Button Class Registration Failed!"), TEXT("ERROR!"), MB_ICONERROR);
                exit(EXIT_FAILURE);
            }
    
            RegisteredClasses.bCustomScrollBar = true;
        }
    
    HWND CreateScrollbar(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
        {
            DWORD ScrollbarStyle = NULL, Child = NULL;
    
            if ((dwStyle & SB_VERT) == SB_VERT)
                ScrollbarStyle = SB_VERT;
            else if ((dwStyle & SB_HORZ) == SB_HORZ)
                ScrollbarStyle = SB_HORZ;
            else
                return NULL;
    
            if ((dwStyle & WS_CHILD) == WS_CHILD)
                Child = WS_CHILD;
            if ((dwStyle & WS_VISIBLE) == WS_VISIBLE)
                Child |= WS_VISIBLE;
    
            RegisterScrollbarClass();
    
            Scrollbar.push_back(CustomScrollbar(ScrollbarStyle, x, y, nWidth, nHeight, (int)hMenu));
            for(unsigned int i = 0; i < Scrollbar.size(); i++)
                Scrollbar.at(i).Create();
    
            if (Scrollbar.at(Scrollbar.size()-1).Create(dwExStyle, lpClassName, NULL, Child, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) != NULL)
            {
                if (Scrollbar.size() == 2)
                    Scrollbar.at(Scrollbar.size() - 1).EnableTransparent(true);
                return Scrollbar.at(Scrollbar.size()-1).WindowHandle();
            }
            else
            {
                Scrollbar.pop_back();
                return NULL;
            }
        }
    
    void RegisterScrollbarClass()
    {
    if(registeredClass.bCustomScrollBar)
    返回;
    WNDCLASSEX wc;
    wc.cbSize=sizeof(WNDCLASSEX);
    wc.style=CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc=BaseWindow::stWinMsgHandler;
    wc.cbClsExtra=0;
    wc.cbWndExtra=0;
    wc.hInstance=NULL;
    wc.hIcon=NULL;
    wc.hCursor=NULL;
    wc.hbrBackground=NULL;
    wc.lpszMenuName=NULL;
    wc.lpszClassName=文本(“自定义滚动条”);
    wc.hIconSm=NULL;
    如果(!RegisterClassEx(&wc))
    {
    MessageBox(NULL,文本(“按钮类注册失败!”)、文本(“错误!”)、MB_ICONERROR);
    退出(退出失败);
    }
    RegisteredClasses.bCustomScrollBar=true;
    }
    HWND CreateScrollbar(DWORD dwExStyle、LPCTSTR lpClassName、LPCTSTR lpWindowName、DWORD dwStyle、int x、int y、int nWidth、int nHeight、HWND hWndParent、HMENU HMENU、HINSTANCE HINSTANCE、LPVOID lpParam)
    {
    DWORD ScrollbarStyle=NULL,Child=NULL;
    if((dwStyle&SB_VERT)==SB_VERT)
    ScrollbarStyle=SB_VERT;
    else if((dwStyle&SB_-HORZ)=SB_-HORZ)
    ScrollbarStyle=SB_HORZ;
    其他的
    返回NULL;
    if((dwStyle&WS_CHILD)==WS_CHILD)
    Child=WS_Child;
    如果((dwStyle&WS_可见)==WS_可见)
    Child |=WS|u可见;
    RegisterScrollbarClass();
    滚动条。向后推(自定义滚动条(滚动条样式,x,y,nWidth,nHeight,(int)humenu));
    for(无符号int i=0;i

    您可以在此处下载示例程序:


    已解决:


    多亏了Raymond Chen,我从我的滚动条课程中删除了
    CS|HREDRAW | CS|u VREDRAW
    ,我的工作就像一个没有
    WS_CLIPCHILDREN
    的魔咒

    WS_CLIPCHILDREN
    与“组框”(按钮带有
    BS_group
    somethingsomething样式)的透明度也非常不兼容。只是观察。这不是我的问题,我只有WS_可见和WS_子标志。我添加了一些代码来解释我的意思。我的滚动条只是一个孤独的窗口:)闪烁来自
    CS|HREDRAW | CS|u VREDRAW
    和你在屏幕上而不是在屏幕下作曲的事实。哇,我没有话。。。我想我检查了
    CS|HREDRAW | CS|u VREDRAW
    ,但它不起作用,但我错了。非常感谢。圣诞快乐:)