如何在一个圆角形状的窗体中绘制一个圆角矩形边框?

3
我正在创建一个具有圆角边框的表单(如此问题中所示)。 与该人遇到的问题相同,我似乎无法绘制圆角边框。 以下是设置实际边框形状的代码:
// ... within InitializeComponent ...
this.FormBorderStyle = FormBorderStyle.None;
IntPtr handle = CreateRoundRectRgn(0, 0, Width, Height, 20, 20);
Region = System.Drawing.Region.FromHrgn(handle);
DeleteObject(handle);

this.ResizeRedraw = true;

这是一段代码,它重写了 OnPaint 方法并绘制出边框轮廓。

protected override void OnPaint(PaintEventArgs e)
{
     // I've tried modifying the parameters here.
     GraphicsPath path = MyRoundedRectangle.Create(0, 0, Width, Height, 10, MyRoundedRectangle.RectangleCorners.All);

     Pen p = new Pen(Brushes.Black, 3f);
     e.Graphics.DrawPath(p, path);
}
MyRoundedRectangle的内容与此问题中提供的代码相同,其中答案链接到此页面,该页面包含MyRoundedRectangle的代码。
我想要一个完整的边框,但实际上我得到的是这样的:this

我认为您可以使用一个透明的窗体(将其TransparencyKey设置为BackColor,选择一种明智的颜色:例如不要红色),然后使用GraphicsPath.AddArc()来绘制圆角背景和边框(如果需要)。您可以参考这里的示例:如何避免带有圆角的可缩放UserControl的彩色边框的视觉伪影?。使用窗体更加容易(透明度效果非常好)。 - Jimi
1个回答

5
一种基本的实现方式如下所述。
frmRoundCorners表单提供了一些属性,允许使用自定义的BackColor、BorderColor和内边框颜色来绘制其圆角区域,并作为表单边框内侧的“阴影”。

表单本身是使用一个基类baseForm实现的,该基类派生自Form,因此可以在表单设计器中设置表单的属性。
通过将表单的原始BackColor设置为其TrasparencyKey来激活透明度,使其ClientArea完全透明但可绘制。基类构造函数中将表单的原始边框设置为FormBorderStyle.None。我没有设置特定的BackColor/TransparencyKey Color(必须在表单的设计器中设置),因为我认为这是需要进行实验的东西。我建议使用中灰色。避免使用红色组件。
表单可以通过单击其ClientArea上的任意点并拖动来移动。
表单的最小/最大曲率及其自定义边框设置为15度和180度。无法使用PropertyGrid将其更改为不同的范围。表单的圆角区域及其边框是使用GraphicsPath.AddArc()方法绘制的,然后在Graphics对象上应用了一个Matrix变换,同时在ScaleTransform(位置)组件中应用了变换。Size组件不受影响。
其外观如下所示:Rounded draggable borderless Form
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

[ToolboxItem(false)]
public partial class frmRoundCorners : baseForm
{
    private GraphicsPath pathRegion = new GraphicsPath(FillMode.Winding);
    private GraphicsPath pathBorder;
    Point pMousePosition = Point.Empty;

    public frmRoundCorners()
    {
        SetStyle(ControlStyles.AllPaintingInWmPaint |
                 ControlStyles.UserPaint |
                 ControlStyles.OptimizedDoubleBuffer |
                 ControlStyles.ResizeRedraw, true);
        InitializeComponent();
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left) {
            pMousePosition = e.Location;
        }
        base.OnMouseDown(e);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left) {
            Point screenPos = PointToScreen(e.Location);
            this.Location = new Point(screenPos.X - pMousePosition.X, screenPos.Y - pMousePosition.Y);
        }
        base.OnMouseMove(e);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
        RoundedCornerRectangle(ClientRectangle);
        RectangleF rect = pathRegion.GetBounds();
        float scaleX = 1 - (BorderSize / rect.Width);
        float scaleY = 1 - (BorderSize / rect.Height);
        using (Pen pen = new Pen(BorderColor, BorderSize))
        using (Pen penBorder = new Pen(InternalBorderColor, 2))
        using (var brush = new SolidBrush(FillColor))
        using (var mx = new Matrix(scaleX, 0, 0, scaleY, (pen.Width / 2), (pen.Width / 2)))
        {
            e.Graphics.Transform = mx;
            e.Graphics.FillPath(brush, pathRegion);
            e.Graphics.DrawPath(penBorder, pathBorder);
            e.Graphics.DrawPath(pen, pathRegion);
        }
    }

    private void RoundedCornerRectangle(Rectangle r)
    {
        pathRegion = new GraphicsPath(FillMode.Alternate);
        float innerCurve = CurveAngle - m_PenSizeOffset;

        pathRegion.StartFigure();
        pathRegion.AddArc(r.X, r.Y, CurveAngle, CurveAngle, 180, 90);
        pathRegion.AddArc(r.Right - CurveAngle, r.Y, CurveAngle, CurveAngle, 270, 90);
        pathRegion.AddArc(r.Right - CurveAngle, r.Bottom - CurveAngle, CurveAngle, CurveAngle, 0, 90);
        pathRegion.AddArc(r.X, r.Bottom - CurveAngle, CurveAngle, CurveAngle, 90, 90);
        pathRegion.CloseFigure();

        pathBorder = new GraphicsPath();
        pathBorder.StartFigure();
        pathBorder.AddArc(r.X + m_PenSizeOffset, r.Y + m_PenSizeOffset, innerCurve, innerCurve, 180, 90);
        pathBorder.AddArc(r.Right - innerCurve - m_PenSizeOffset, r.Y + m_PenSizeOffset, innerCurve, innerCurve, 270, 90);
        pathBorder.AddArc(r.Right - innerCurve - m_PenSizeOffset, r.Bottom - innerCurve- m_PenSizeOffset, innerCurve, innerCurve, 0, 90);
        pathBorder.AddArc(r.X + m_PenSizeOffset, r.Bottom - innerCurve - m_PenSizeOffset, innerCurve, innerCurve, 90, 90);
        pathBorder.CloseFigure();
    }
}

baseForm 类:

public class baseForm : Form
{
    private Color m_InternalBorderColor = Color.FromArgb(128, 128, 128);
    private Color m_BorderColor = Color.Red;
    private Color m_FillColor = Color.WhiteSmoke;
    private float m_PenSize = 6f;
    private float m_CurveAngle = 60.0f;
    internal float m_PenSizeOffset = 3f;

    public baseForm() => InitializeComponent();
    private void InitializeComponent() => FormBorderStyle = FormBorderStyle.None;

    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [DefaultValue(60.0f)]
    public virtual float CurveAngle
    {
        get => m_CurveAngle;
        set {
            m_CurveAngle = Math.Max(Math.Min(value, 180), 15);
            Invalidate();
        }
    }
    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [DefaultValue(6.0f)]
    public virtual float BorderSize
    {
        get => m_PenSize;
        set {
            m_PenSize = value;
            m_PenSizeOffset = value / 2.0f;
            Invalidate();
        }
    }

    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public virtual Color BorderColor
    {
        get => m_BorderColor;
        set {
            m_BorderColor = value;
            Invalidate();
        }
    }

    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public virtual Color FillColor
    {
        get => m_FillColor;
        set {
            m_FillColor = value;
            Invalidate();
        }
    }

    [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), Category("Appearance")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [Description("Get or Set the Color of the internal border")]
    public virtual Color InternalBorderColor
    {
        get => m_InternalBorderColor;
        set {
            m_InternalBorderColor = value;
            Invalidate();
        }
    }

    [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [DefaultValue(FormBorderStyle.None)]
    public new FormBorderStyle FormBorderStyle
    {
        get => base.FormBorderStyle;
        set => base.FormBorderStyle = FormBorderStyle.None;
    }
}

我正在寻找类似的东西。谢谢! - preciousbetine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接