为什么带有渐变填充的 RoundRect 路径不能在右侧产生正确的角?
Why doesn't the RoundRect path with gradient fill produce the correct corners on right side?
我想出了一个创建渐变填充的圆角矩形(按钮)的例程,但是如果我省略写轮廓的代码,右下角看起来是正方形,右上角看起来不太像对吧。这是为什么?
注意:自绘按钮创建为 23x23。
//-------------------------------------------------------------------------
// Purpose: Draw a rounded rectangle for owner-draw button
//
// Input: dis - [i] owner-draw information structure
// undermouse - [i] flag if button is under mouse
//
// Output: na
//
// Notes: This creates a standard grey type rounded rectangle for owner
// drawn buttons.
//
// This routine does not currently use undermouse to change
// gradient
//
void DrawRoundedButtonRectangle(const DRAWITEMSTRUCT& dis, BOOL undermouse)
{
UNREFERENCED_PARAMETER(undermouse);
// save DC before we modify it.
SaveDC(dis.hDC);
// create a path for the round rectangle (right/bottom is RECT format of +1)
BeginPath(dis.hDC);
RoundRect(dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom, 6, 6);
EndPath(dis.hDC);
// save DC before changing clipping region
SaveDC(dis.hDC);
// set clipping region to be the path
SelectClipPath(dis.hDC, RGN_COPY);
TRIVERTEX vertices[2];
// setup the starting location and color (light grey)
vertices[0].x = dis.rcItem.left;
vertices[0].y = dis.rcItem.top;
vertices[0].Red = MAKEWORDHL(211, 0);
vertices[0].Green = MAKEWORDHL(211, 0);
vertices[0].Blue = MAKEWORDHL(211, 0);
vertices[0].Alpha = 0xffff;
// setup the ending location and color (grey)
vertices[1].x = dis.rcItem.right; // should this be -1 ?
vertices[1].y = dis.rcItem.bottom; // should this be -1 ?
vertices[1].Red = MAKEWORDHL(150, 0);
vertices[1].Green = MAKEWORDHL(150, 0);
vertices[1].Blue = MAKEWORDHL(150, 0);
vertices[1].Alpha = 0xffff;
// setup index to use for left to right
GRADIENT_RECT r[1];
r[0].UpperLeft = 0;
r[0].LowerRight = 1;
// fill the DC with a vertical gradient
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
// go back to original clipping area
RestoreDC(dis.hDC, -1);
// change the path to be the outline border
if (WidenPath(dis.hDC)) {
// set clipping region to be the path
SelectClipPath(dis.hDC, RGN_COPY);
// create a gradient on the outline
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
}
// put back the DC as we received it
RestoreDC(dis.hDC, -1);
}
图中红色为背景。
删除 WidenPath
部分时会生成错误按钮。
根据你的描述,我想你说的可能是这种情况。
BeginPath(dis.hDC);
// RoundRect(dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom, 6, 6);
EndPath(dis.hDC);
我先分析一下为什么会得到这个形状
重绘按钮时,如果重绘按钮的长宽小于按钮本身,只会重绘一部分。
case WM_CREATE:
{
//Button width:230 Button height:230
button = CreateRoundRectButton(hWnd, 500, 200, 230, 230, 30, 30, BTN_ID);
return 0;
}
break;
case WM_DRAWITEM:
{
DRAWITEMSTRUCT dis;
dis.CtlType = ODT_BUTTON;
dis.CtlID = BTN_ID;
dis.hDC = GetDC(button);
dis.rcItem.left = 0;
dis.rcItem.top = 0;
dis.rcItem.right = 200; //Width of redrawing
dis.rcItem.bottom = 200; //Height of redrawing
DrawRoundedButtonRectangle(dis, TRUE);
}
为了更清楚的看到效果,我把宽高加宽了
如果我省略写大纲的代码,它只执行下面的代码来实现渐变
// fill the DC with a vertical gradient
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
如果我改变重绘的XY坐标。
实际上,当您禁用 RoundRect
时,唯一有效的是 GradientFill
。
更新:
重绘区域以rcItem
为准。当你画一条路径时,它只考虑内部区域而轮廓不是,所以 WidenPath
然后继续轮廓并给出真正的路由 rect
区域。
我想出了一个创建渐变填充的圆角矩形(按钮)的例程,但是如果我省略写轮廓的代码,右下角看起来是正方形,右上角看起来不太像对吧。这是为什么?
注意:自绘按钮创建为 23x23。
//-------------------------------------------------------------------------
// Purpose: Draw a rounded rectangle for owner-draw button
//
// Input: dis - [i] owner-draw information structure
// undermouse - [i] flag if button is under mouse
//
// Output: na
//
// Notes: This creates a standard grey type rounded rectangle for owner
// drawn buttons.
//
// This routine does not currently use undermouse to change
// gradient
//
void DrawRoundedButtonRectangle(const DRAWITEMSTRUCT& dis, BOOL undermouse)
{
UNREFERENCED_PARAMETER(undermouse);
// save DC before we modify it.
SaveDC(dis.hDC);
// create a path for the round rectangle (right/bottom is RECT format of +1)
BeginPath(dis.hDC);
RoundRect(dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom, 6, 6);
EndPath(dis.hDC);
// save DC before changing clipping region
SaveDC(dis.hDC);
// set clipping region to be the path
SelectClipPath(dis.hDC, RGN_COPY);
TRIVERTEX vertices[2];
// setup the starting location and color (light grey)
vertices[0].x = dis.rcItem.left;
vertices[0].y = dis.rcItem.top;
vertices[0].Red = MAKEWORDHL(211, 0);
vertices[0].Green = MAKEWORDHL(211, 0);
vertices[0].Blue = MAKEWORDHL(211, 0);
vertices[0].Alpha = 0xffff;
// setup the ending location and color (grey)
vertices[1].x = dis.rcItem.right; // should this be -1 ?
vertices[1].y = dis.rcItem.bottom; // should this be -1 ?
vertices[1].Red = MAKEWORDHL(150, 0);
vertices[1].Green = MAKEWORDHL(150, 0);
vertices[1].Blue = MAKEWORDHL(150, 0);
vertices[1].Alpha = 0xffff;
// setup index to use for left to right
GRADIENT_RECT r[1];
r[0].UpperLeft = 0;
r[0].LowerRight = 1;
// fill the DC with a vertical gradient
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
// go back to original clipping area
RestoreDC(dis.hDC, -1);
// change the path to be the outline border
if (WidenPath(dis.hDC)) {
// set clipping region to be the path
SelectClipPath(dis.hDC, RGN_COPY);
// create a gradient on the outline
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
}
// put back the DC as we received it
RestoreDC(dis.hDC, -1);
}
图中红色为背景。
删除 WidenPath
部分时会生成错误按钮。
根据你的描述,我想你说的可能是这种情况。
BeginPath(dis.hDC);
// RoundRect(dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right, dis.rcItem.bottom, 6, 6);
EndPath(dis.hDC);
我先分析一下为什么会得到这个形状
重绘按钮时,如果重绘按钮的长宽小于按钮本身,只会重绘一部分。
case WM_CREATE:
{
//Button width:230 Button height:230
button = CreateRoundRectButton(hWnd, 500, 200, 230, 230, 30, 30, BTN_ID);
return 0;
}
break;
case WM_DRAWITEM:
{
DRAWITEMSTRUCT dis;
dis.CtlType = ODT_BUTTON;
dis.CtlID = BTN_ID;
dis.hDC = GetDC(button);
dis.rcItem.left = 0;
dis.rcItem.top = 0;
dis.rcItem.right = 200; //Width of redrawing
dis.rcItem.bottom = 200; //Height of redrawing
DrawRoundedButtonRectangle(dis, TRUE);
}
为了更清楚的看到效果,我把宽高加宽了
如果我省略写大纲的代码,它只执行下面的代码来实现渐变
// fill the DC with a vertical gradient
GradientFill(dis.hDC, vertices, _countof(vertices), r, _countof(r), GRADIENT_FILL_RECT_V);
如果我改变重绘的XY坐标。
实际上,当您禁用 RoundRect
时,唯一有效的是 GradientFill
。
更新:
重绘区域以rcItem
为准。当你画一条路径时,它只考虑内部区域而轮廓不是,所以 WidenPath
然后继续轮廓并给出真正的路由 rect
区域。