绕过WS_CLIPCHILDREN

时间:2013-12-23 19:27:20

标签: c++ winapi

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

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标志来防止这种情况,但是我的滚动条会失去它的透明度,因为我不再无法使子窗口拥有的部分无效。

到目前为止我尝试过:

  1. 在使父级无效之前,我删除了WS_CLIPCHILDREN标记,重新绘制,然后重新设置WS_CLIPCHILDREN标记。 [结果:它工作正常,但是我的CPU使用率超过了30%,所以这是不行的。]

  2. 在删除和重新绘制之前,尝试验证子窗口(没有WS_CLIPCHILDREN)。 [结果:没有用,不知道为什么......也许我......不知道。]

  3. 完全禁用了我的滚动条中的所有重新绘制(没有WS_CLIPCHILDREN)[结果:无效,仍然闪烁。]

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

    编辑:

    有关如何创建滚动条的更多信息。在下面的代码中,您可以看到我的滚动条只是一个带有WS_VISIBLEWS_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;
            }
        }
    

    您可以在此下载示例程序:http://www.putlocker.com/file/B8704C613BC7EC96


    解决:

    感谢Raymond Chen,我从我的Scroll bar课程中删除了CS_HREDRAW | CS_VREDRAW,我的工作就像没有WS_CLIPCHILDREN的魅力。

0 个答案:

没有答案