我想创建一个渐变背景的静态控件。
我想通过以下方式实现:
在主窗口的背景中创建渐变,然后将透明静态控件放在该背景的顶部。
为此,我在RECT
处理程序中创建了WM_PAINT
变量,将渐变定位在静态控制所在的位置。
另外,我尝试使用双缓冲来避免闪烁(我还处理了WM_ERASEBKGND
,从窗口类中删除了标记CS_VREDRAW
和CS_HREDRAW
。
我还处理了WM_SIZE
消息以使窗口无效,并正确地重新定位静态控件。
在我的WM_CTLCOLORSTATIC
处理程序中,我已返回NULL_BRUSH
。
我已经通过Visual Studio中的应用程序向导制作了一个演示应用程序来说明这一点。
我在Windows XP上工作,使用纯Win32 API和C ++。
Bellow我将提交WM_PAINT
的修改代码,以及上面列出的其他处理程序的代码段:
case WM_CREATE:
{
// get rectangle dimensions of the main window
RECT rec;
GetClientRect( hWnd, &rec );
/******* main window's static control ******/
HWND StaticControl = CreateWindowEx( 0, L"Static", L"",
WS_VISIBLE | WS_CHILD | SS_NOTIFY,
( 3 * ( rec.right - rec.left ) / 4 - 340 ) / 3,
120 + ( rec.bottom - rec.top - 450 ) / 3,
150, 150, hWnd, (HMENU)4000, hInst, 0);
}
return (LRESULT)0;
case WM_SIZE:
{
RECT rec; // main window's client rectangle
GetClientRect( hWnd, &rec );
SetWindowPos( GetDlgItem( hWnd, 4000 ),
NULL,
( 3 * ( rec.right - rec.left ) / 4 - 340 ) / 3,
120 + ( rec.bottom - rec.top - 450 ) / 3, 150, 150,
SWP_NOZORDER );
InvalidateRect( hWnd, NULL, FALSE);
}
return (LRESULT)0;
case WM_ERASEBKGND:
return (LRESULT)1;
case WM_CTLCOLORSTATIC:
return (LRESULT)( (HBRUSH)GetStockObject(NULL_BRUSH) );
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
RECT r; // rectangle for main window's client area
GetClientRect( hWnd, &r);
HDC MemDC = CreateCompatibleDC(hdc); // back buffer
// compatible bitmap for MemDC
HBITMAP bmp = CreateCompatibleBitmap( hdc,
r.right - r.left,
r.bottom - r.top ),
oldBmp = (HBITMAP)SelectObject( MemDC, bmp ); // needed for cleanup
/***** draw a reference header at the top of the window *******/
// position it properly at the top
RECT rect;
rect.left = r.left;
rect.top = r.top;
rect.right = r.right;
rect.bottom = 120;
FillRect( MemDC, &rect, (HBRUSH)GetStockObject(LTGRAY_BRUSH) );
/**** main window's gradient background *******/
//============ down triangle =========//
TRIVERTEX vertex[3];
vertex[0].x = r.right;
vertex[0].y = r.bottom - r.top;
vertex[0].Red = 0xDB00;
vertex[0].Green = 0xE500;
vertex[0].Blue = 0xF100;
vertex[0].Alpha = 0x0000;
vertex[1].x = r.left;
vertex[1].y = r.bottom - r.top;
vertex[1].Red = 0x9500;
vertex[1].Green = 0xB300;
vertex[1].Blue = 0xD700;
vertex[1].Alpha = 0x0000;
vertex[2].x = r.left;
vertex[2].y = r.top + 120;
vertex[2].Red = 0xDB00;
vertex[2].Green = 0xE500;
vertex[2].Blue = 0xF100;
vertex[2].Alpha = 0x0000;
// Create a GRADIENT_TRIANGLE structure that
// references the TRIVERTEX vertices.
GRADIENT_TRIANGLE gTriangle;
gTriangle.Vertex1 = 0;
gTriangle.Vertex2 = 1;
gTriangle.Vertex3 = 2;
// Draw a shaded triangle.
GradientFill( MemDC, vertex, 3, &gTriangle, 1, GRADIENT_FILL_TRIANGLE);
//=============== upper triangle =================//
TRIVERTEX vertex1[3];
vertex1[0].x = r.right;
vertex1[0].y = r.bottom - r.top;
vertex1[0].Red = 0xDB00;
vertex1[0].Green = 0xE500;
vertex1[0].Blue = 0xF100;
vertex1[0].Alpha = 0x0000;
vertex1[1].x = r.right;
vertex1[1].y = r.top + 120;
vertex1[1].Red = 0x9500;
vertex1[1].Green = 0xB300;
vertex1[1].Blue = 0xD700;
vertex1[1].Alpha = 0x0000;
vertex1[2].x = r.left;
vertex1[2].y = r.top + 120;
vertex1[2].Red = 0xDB00;
vertex1[2].Green = 0xE500;
vertex1[2].Blue = 0xF100;
vertex1[2].Alpha = 0x0000;
// Draw a shaded triangle.
GradientFill( MemDC, vertex1, 3, &gTriangle, 1, GRADIENT_FILL_TRIANGLE);
//**** draw background of the static control ****//
//position it properly
rect.left = ( 3 * ( r.right - r.left ) / 4 - 340 ) / 3;
rect.top = 120 + ( r.bottom - r.top - 450 ) / 3;
rect.right = 150 + ( 3 * ( r.right - r.left ) / 4 - 340 ) / 3;
rect.bottom = 270 + ( r.bottom - r.top - 450 ) / 3; // this one fails!!!
//FillRect( MemDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH) );
// vertexes for static's gradient color
//================= top rectangle =====================//
TRIVERTEX vertexS[2], vertex1S[2] ;
vertexS[0].x = rect.left;
vertexS[0].y = rect.top;
vertexS[0].Red = 0x9500;
vertexS[0].Green = 0xB300;
vertexS[0].Blue = 0xD700;
vertexS[0].Alpha = 0x0000;
vertexS[1].x = rect.right;
vertexS[1].y = ( rect.bottom - rect.top ) / 2;
vertexS[1].Red = 0x4F00;
vertexS[1].Green = 0x8B00;
vertexS[1].Blue = 0xBD00;
vertexS[1].Alpha = 0x0000;
//================== bottom rectangle ====================//
vertex1S[0].x = rect.left;
vertex1S[0].y = ( rect.bottom - rect.top ) / 2;
vertex1S[0].Red = 0x4F00;
vertex1S[0].Green = 0x8B00;
vertex1S[0].Blue = 0xBD00;
vertex1S[0].Alpha = 0x0000;
vertex1S[1].x = rect.right;
vertex1S[1].y = rect.bottom;
vertex1S[1].Red = 0x9500;
vertex1S[1].Green = 0xB300;
vertex1S[1].Blue = 0xD700;
vertex1S[1].Alpha = 0x0000;
// Create a GRADIENT_RECT structure that
// references the TRIVERTEX vertices.
GRADIENT_RECT gRect;
gRect.UpperLeft = 0;
gRect.LowerRight = 1;
// Draw a shaded rectangle.
GradientFill( MemDC, vertexS, 2, &gRect, 1, GRADIENT_FILL_RECT_V );
GradientFill( MemDC, vertex1S, 2, &gRect, 1, GRADIENT_FILL_RECT_V );
/****** draw back buffer on the screen DC *****************/
BitBlt( hdc, 0, 0, r.right - r.left, r.bottom - r.top,
MemDC, 0, 0, SRCCOPY );
/************** cleanup *******************/
SelectObject( MemDC, oldBmp );
DeleteObject(bmp); // compatible bitmap for MemDC
DeleteDC(MemDC);
EndPaint(hWnd, &ps);
}
return (LRESULT)0;
当我在GradientFill
处理程序中使用WM_PAINT
API时,屏幕上会出现一个比它应该更大的矩形。
贝娄图片说明了这个结果:
如果我尝试使用实心画笔填充相同的矩形,一切正常。
贝娄图片说明了这个结果:
我在设置了矩形坐标的地方放置了断点,但没有看到任何问题。
此外,GradientFill
会返回TRUE
,因此不会失败。
如何解决这个问题?
提前谢谢。
问候。
答案 0 :(得分:1)
我认为只是你对顶点的计算是错误的:
vertexS[1].y = ( rect.bottom - rect.top ) / 2;
/* .... */
vertex1S[0].y = ( rect.bottom - rect.top ) / 2;
它们应该是rect.top + ( rect.bottom - rect.top ) / 2
还是类似的?或者甚至只分别是rect.bottom
和rect.top
?
这取决于你想要实现的目标,但无论哪种方式,我认为它目前不是你想要的。您需要使用rect.bottom
和rect.top
来获得与已注释掉的FillRect
相同的形状。