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看起来是错误的,但事实并非如此。有关参考,请参阅。