我使用GDI +绘制圆角矩形的每个示例代码都是这样的(从BobPowell.net解除并略微修改):
Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Panel1.Paint
e.Graphics.Clear(SystemColors.Window)
e.Graphics.SmoothingMode = SmoothingMode.None
Call DrawRoundRect(e.Graphics, Pens.Red, 10, 10, 48, 24, 6)
End Sub
Public Sub DrawRoundRect(ByVal g As Graphics, ByVal p As Pen, ByVal x As Single, ByVal y As Single, ByVal width As Single, ByVal height As Single, ByVal radius As Single)
Using gp As New GraphicsPath()
gp.StartFigure()
gp.AddArc(x + width - radius, y, radius * 2, radius * 2, 270, 90)
gp.AddArc(x + width - radius, y + height - radius, radius * 2, radius * 2, 0, 90)
gp.AddArc(x, y + height - radius, radius * 2, radius * 2, 90, 90)
gp.AddArc(x, y, radius * 2, radius * 2, 180, 90)
gp.CloseFigure()
g.DrawPath(p, gp)
End Using
End Sub
这会产生一个圆角矩形,只有左上角是准确的。
AntiAliasing必须关闭,因为它正在通过远程桌面连接,我不能依赖它可用。此外,我正在寻找一个清晰的圆角矩形。
我已经尝试调整其他角落的大小并更改笔对齐,但似乎没有任何东西可以生成简单,精确的圆角矩形。
有没有办法在旧的winforms中绘制比这更好的圆角矩形?
答案 0 :(得分:3)
1)将源图像的大小调整为其原始大小的二进制倍数。通常情况下,我会重新采样到比原始宽度和高度高4倍(或8或16)的宽度和高度。
2)执行我所有的GDI +绘图操作(当然,考虑到我的坐标需要乘以4倍)。没有必要使用任何花哨的抗锯齿。
3)将图像重新采样回原始尺寸。缩小图像会产生很好的平滑效果,并最大限度地减少线条,曲线等中的任何舍入误差。
private Bitmap GenerateButton(int overSampling) {
int overSampling = 8;
int width=(48 + 10 + 10 + 6) * overSampling;
int height=(24 + 10 + 10 + 6) * overSampling;
// Draw the button with the rounded corners, but do
// so at 8 times the normal size.
Bitmap bitmap=new Bitmap(width,height);
using (Graphics g = Graphics.FromImage(bitmap)) {
g.Clear(Color.White);
g.SmoothingMode = SmoothingMode.None;
DrawRoundRect(overSampling, g, new Pen(Color.Red, overSampling), 10, 10, 48, 24, 6);
}
// Shrink the image down to its intended size
Bitmap shrunkVersion=new Bitmap(bitmap.Width / overSampling, bitmap.Height / overSampling);
using (Graphics g = Graphics.FromImage(shrunkVersion)) {
// Use hi-quality resampling for a nice, smooth image.
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(bitmap, 0, 0, shrunkVersion.Width, shrunkVersion.Height);
}
return shrunkVersion;
}
private void DrawRoundRect(int overSampling, Graphics g, Pen p, float x, float y, float width, float height, float radius)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.StartFigure();
gp.AddArc((x + width - radius) * overSampling, y * overSampling, (radius * 2) * overSampling, (radius * 2) * overSampling, 270, 90);
gp.AddArc((x + width - radius) * overSampling, (y + height - radius) * overSampling, (radius * 2) * overSampling, (radius * 2) * overSampling, 0, 90);
gp.AddArc(x * overSampling, (y + height - radius) * overSampling, radius * 2 * overSampling, radius * 2 * overSampling, 90, 90);
gp.AddArc(x * overSampling, y * overSampling, radius * 2 * overSampling, radius * 2 * overSampling, 180, 90);
gp.CloseFigure();
g.DrawPath(p, gp);
}
}
没有过采样:
进行8次过采样:
答案 1 :(得分:2)
我找到了最好的解决方案,只是老派的Windows API:
Private Sub DrawRoundRect(ByVal g As Graphics, ByVal r As Rectangle)
Dim hDC As IntPtr = g.GetHdc
Dim hPen As IntPtr = CreatePen(PS_SOLID, 0, ColorTranslator.ToWin32(Color.Red))
Dim hOldPen As IntPtr = SelectObject(hDC, hPen)
SelectObject(hDC, GetStockObject(NULL_BRUSH))
RoundRect(hDC, r.Left, r.Top, r.Right - 1, r.Bottom - 1, 12, 12)
SelectObject(hDC, hOldPen)
DeleteObject(hPen)
g.ReleaseHdc(hDC)
End Sub
这会生成我一直在寻找的对称圆角矩形:
答案 2 :(得分:1)
因为在这里没有人回答你这是我过去使用的一个技巧。它运行得相当好,并且看起来比使用AddArc()的经典实现更好。
它使用圆和剪裁来达到你想要的效果。当使用宽度大于1px的笔时,它可能会显示轻微的伪影,但除此之外它还能正常工作。
我希望它对你的项目来说足够好。
private void DrawRoundedRectangle(Graphics g, Pen pen, Rectangle rect, int radius)
{
g.DrawLine(pen, rect.Left + radius, rect.Top, rect.Right - radius, rect.Top);
g.DrawLine(pen, rect.Right, rect.Top+radius, rect.Right, rect.Bottom - radius);
g.DrawLine(pen, rect.Left + radius, rect.Bottom, rect.Right - radius, rect.Bottom);
g.DrawLine(pen, rect.Left, rect.Top + radius, rect.Left, rect.Bottom - radius);
g.SetClip(new Rectangle(rect.Left, rect.Top, radius, radius));
g.DrawEllipse(pen, rect.Left, rect.Top, radius * 2, radius * 2);
g.ResetClip();
g.SetClip(new Rectangle(rect.Right-radius, rect.Top, radius+1, radius+1));
g.DrawEllipse(pen, rect.Right - radius * 2, rect.Top, radius * 2, radius * 2);
g.ResetClip();
g.SetClip(new Rectangle(rect.Right - radius, rect.Bottom-radius, radius+1, radius+1));
g.DrawEllipse(pen, rect.Right - radius * 2, rect.Bottom - (radius * 2), radius * 2, radius * 2);
g.ResetClip();
g.SetClip(new Rectangle(rect.Left, rect.Bottom - radius, radius+1, radius+1));
g.DrawEllipse(pen, rect.Left, rect.Bottom - (radius * 2), radius * 2, radius * 2);
g.ResetClip();
}
该方法的界面很简单,但如果您需要帮助,请发表评论。
编辑:其他应该工作的是将相同的弧绘制四次,但是使用TranslateTransform和TranslateScale进行翻转。那个 意味着弧在每个角落看起来都是相同的。
private void DrawRoundedRectangle(Graphics g, Pen pen, Rectangle rect, int radius)
{
g.DrawLine(pen, rect.Left + radius, rect.Top, rect.Right - radius, rect.Top);
g.DrawLine(pen, rect.Right-1, rect.Top+radius, rect.Right-1, rect.Bottom - radius);
g.DrawLine(pen, rect.Left + radius, rect.Bottom-1, rect.Right - radius, rect.Bottom-1);
g.DrawLine(pen, rect.Left, rect.Top + radius, rect.Left, rect.Bottom - radius);
g.TranslateTransform(rect.Left, rect.Top);
g.DrawArc(pen, 0, 0, radius * 2, radius * 2, 180, 90);
g.ResetTransform();
g.TranslateTransform(rect.Right, rect.Top);
g.ScaleTransform(-1, 1);
g.DrawArc(pen, 1, 0, radius * 2, radius * 2, 180, 90);
g.ResetTransform();
g.TranslateTransform(rect.Right, rect.Bottom);
g.ScaleTransform(-1, -1);
g.DrawArc(pen, 1, 1, radius * 2, radius * 2, 180, 90);
g.ResetTransform();
g.TranslateTransform(rect.Left, rect.Bottom);
g.ScaleTransform(1, -1);
g.DrawArc(pen, 0, 1, radius * 2, radius * 2, 180, 90);
g.ResetTransform();
}
这类似于绘制圆形的旧计算机图形方法,您可以在其中绘制四分之一圆,以避免舍入错误,例如GDI中的错误。
另一种方法是将第一个弧线绘制到图像上,然后将图像绘制四次,根据需要进行翻转。下面是第二种方法的变体,使用图像绘制弧线。
private void DrawRoundedRectangle(Graphics g, Pen pen, Rectangle rect, int radius)
{
g.DrawLine(pen, rect.Left + radius, rect.Top, rect.Right - radius, rect.Top);
g.DrawLine(pen, rect.Right - 1, rect.Top + radius, rect.Right - 1, rect.Bottom - radius);
g.DrawLine(pen, rect.Left + radius, rect.Bottom - 1, rect.Right - radius, rect.Bottom - 1);
g.DrawLine(pen, rect.Left, rect.Top + radius, rect.Left, rect.Bottom - radius);
Bitmap arc = new Bitmap(radius, radius, g);
Graphics.FromImage(arc).DrawArc(pen, 0, 0, radius * 2, radius * 2, 180, 90);
g.TranslateTransform(rect.Left, rect.Top);
g.DrawImage(arc, 0, 0);
g.ResetTransform();
g.TranslateTransform(rect.Right, rect.Top);
g.ScaleTransform(-1, 1);
g.DrawImage(arc, 0, 0);
g.ResetTransform();
g.TranslateTransform(rect.Right, rect.Bottom);
g.ScaleTransform(-1, -1);
g.DrawImage(arc, 0, 0);
g.ResetTransform();
g.TranslateTransform(rect.Left, rect.Bottom);
g.ScaleTransform(1, -1);
g.DrawImage(arc, 0, 0);
g.ResetTransform();
arc.Dispose();
}
答案 3 :(得分:1)
有时,我使用“低技术”的方法来处理GDI +中的舍入错误
1)将源图像的大小调整为其原始大小的二进制倍数。通常情况下,我会重新采样到比原始宽度和高度高4倍(或8或16)的宽度和高度。
2)执行我所有的GDI +绘图操作(当然,考虑到我的坐标需要乘以4倍)。没有必要使用任何花哨的抗锯齿。
3)将图像重新采样回原始尺寸。缩小图像会产生很好的平滑效果,并最大限度地减少线条,曲线等中的任何舍入误差。