C++ 如何使用FillRect()绘制子窗口?

C++ 如何使用FillRect()绘制子窗口?,c++,winapi,paint,gdi,win32gui,C++,Winapi,Paint,Gdi,Win32gui,我有一个使用以下样式创建的主窗口 WS_-CAPTION | WS_-MINIMIZEBOX | WS_-SYSMENU | WS_-TABSTOP | WS_-GROUP | WS_-VISIBLE 并且带有exstles WS_-EX_-ACCEPTFILES | WS_-EX_-CONTROLPARENT | WS_-EX_-LEFT | WS_-EX-ltr阅读 此主窗口上有一个子窗口,它是使用样式创建的编辑控件 WS|u VISIBLE | WS|u CHILD | ES|u READ

我有一个使用以下样式创建的主窗口
WS_-CAPTION | WS_-MINIMIZEBOX | WS_-SYSMENU | WS_-TABSTOP | WS_-GROUP | WS_-VISIBLE

并且带有exstles
WS_-EX_-ACCEPTFILES | WS_-EX_-CONTROLPARENT | WS_-EX_-LEFT | WS_-EX-ltr阅读

此主窗口上有一个子窗口,它是使用样式创建的编辑控件
WS|u VISIBLE | WS|u CHILD | ES|u READONLY

和ex样式
WS_EX_CLIENTEDGE

我将使用此编辑控件作为进度条控件。我不想使用标准Wind32进度条控件(
progress\u CLASS
),因为我想在其上进行一些自定义绘制(例如,动态更改填充颜色,在其上显示文本等)

我可以通过以下代码绘制主窗口的任何区域:

// hWnd: Handle of the main window  
case WM_PAINT:
    hDc = BeginPaint(hWnd, &Ps);
        Rect = AFunctionToGetCornerThePointsOfTheEditControl();
        Rect.right = Rect.left + 3 * (Rect.right - Rect.left) / 4; // Fill 3/4 (75%) of it
        Rect.left   -= 10; // Enlarge the paint region a little
        Rect.top    -= 10; // so that we can see it if it stays
        Rect.bottom += 10; // under the edit control.
        hBrush = CreateSolidBrush(RGB(50,100,255));
        ret = FillRect(hDc, &Rect, hBrush); // ret = 1 always
        ler = GetLastError();               // ler = 0 
    EndPaint(hWnd, &Ps);
    break;
看起来是这样的:

我稍微修改了这段代码,以绘制子控件:

// hWndEdit: Handle of the edit control
case WM_PAINT:
    hDc = BeginPaint(hWndEdit, &Ps);
        Rect = AFunctionToGetCornerThePointsOfTheEditControl();
        Rect.right = Rect.left + 3 * (Rect.right - Rect.left) / 4; // Fill 3/4 (75%) of it
        Rect.left   -= 10;
        Rect.top    -= 10;
        Rect.bottom += 10;
        hBrush = CreateSolidBrush(RGB(50,100,255));
        ret = FillRect(hDc, &Rect, hBrush); // ret = 0 always
        ler = GetLastError();               // ler = 6 (ERROR_INVALID_HANDLE) 
    EndPaint(hWndEdit, &Ps);
    break;
这次不行了。当我将主窗口的某个部分拖出屏幕区域时,主窗口就会完全消失,并且完全没有响应。它下面的桌面图标可见,但不可单击


那么,为了绘制子窗口(编辑控件),我必须做些什么呢?

WM\u您正在处理的绘制是主窗口的。您需要在其所有者WM_PAINT消息中绘制editbox。我猜您是从“hDc=BeginPaint(hWndEdit,&Ps);”中得到错误的,您可以检查它。

这篇文章对我帮助很大:

首先,我创建一个单独的消息处理函数来处理子消息

LRESULT CALLBACK MyClass::ChildWindowProc(  HWND        hWnd,
                                            UINT        uMsg,
                                            WPARAM      wParam,
                                            LPARAM      lParam,
                                            UINT_PTR    uIdSubclass,
                                            DWORD_PTR   dwRefData)
{
    static PAINTSTRUCT Ps;
    static RECT Rect;
    static HBRUSH hBrush1 = CreateSolidBrush(RGB(50,100,255));
    static HBRUSH hBrush2 = CreateSolidBrush(RGB(255,100,50));
    HDC hDc;
    LRESULT lResult;
    switch (uMsg)
    {
        case WM_PAINT:
            switch (uIdSubclass)
            {
                case 1:
                    hDc = BeginPaint(hWnd, &Ps);
                        Rect.left   = 0;
                        Rect.right  = (LONG) (((double) ITEM2_WIDTH) * Status::GI()->Get_JobCurPercentage());
                        Rect.top    = 0;
                        Rect.bottom = ITEM_HEIGHT - 3;
                        FillRect(hDc, &Rect, hBrush1);
                    EndPaint(hWnd, &Ps);
                    break;
                case 2:
                    hDc = BeginPaint(hWnd, &Ps);
                        Rect.left   = 0;
                        Rect.right  = (LONG) (((double) ITEM2_WIDTH) * Status::GI()->Get_JobTotPercentage());
                        Rect.top    = 0;
                        Rect.bottom = ITEM_HEIGHT - 3;
                        FillRect(hDc, &Rect, hBrush2);
                    EndPaint(hWnd, &Ps);
                    break;
                default:
                    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
            }
            break;
        case WM_NCDESTROY:
            //ReleaseDC(hWnd, hDc);
            return DefSubclassProc(hWnd, uMsg, wParam, lParam);
            break;
        default:
            return DefSubclassProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}
接下来,我将此函数绑定到控件:

SetWindowSubclass(  /*_In_  HWND            hWnd*/          ed_cur_Progress.hWnd,
                    /*_In_  SUBCLASSPROC    pfnSubclass*/   ChildWindowProc,
                    /*_In_  UINT_PTR        uIdSubclass*/   1,
                    /*_In_  DWORD_PTR       dwRefData*/     (DWORD_PTR) NULL);
SetWindowSubclass(  /*_In_  HWND            hWnd*/          ed_tot_Progress.hWnd,
                    /*_In_  SUBCLASSPROC    pfnSubclass*/   ChildWindowProc,
                    /*_In_  UINT_PTR        uIdSubclass*/   2,
                    /*_In_  DWORD_PTR       dwRefData*/     (DWORD_PTR) NULL);
就这些!结果是惊人的


进行自定义绘制的正确方法是对其进行子类化。从
BeginPaint
返回的设备上下文不应通过调用
ReleaseDC
进行松弛。更糟糕的是,您正在将未初始化的
HDC
变量传递给
WM\u DESTROY
处理程序中的
ReleaseDC
。关于清理的另一个注意事项:
WM\u NCDESTROY
是发送到窗口的最后一条消息。这就是你应该把清理代码放在那里的地方。@Tim感谢你提供的信息;我将根据它更改我的代码。那么,如何释放设备上下文?我是否首先释放它?当您调用
EndPaint
时,系统将释放从
BeginPaint
返回的与设备上下文相关的资源。我明白,留下一个悬空的HDC看起来是错误的,但事实并非如此。有关参考,请参阅。