wingform 圆型按钮 可调节



 
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    /// <summary>
    /// 自定义按钮控件(支持正常/悬停/点击状态颜色、文字、圆角、hover效果)
    /// </summary>
namespace WindowsFormsTest.FECLS.Controls
    {
        /// <summary>
        /// 半圆角自定义按钮(4个角为标准半圆,支持颜色/文字/hover/点击效果)
        /// </summary>
        public class SemiCircleButton : Control
        {
            #region 可自定义属性(设计时/代码中均可设置)
            /// <summary>
            /// 正常状态背景色(默认:深蓝色 #2563EB)
            /// </summary>
            [Category("自定义样式")]
            [Description("按钮正常状态的背景色")]
            public Color NormalBackColor { get; set; } = Color.FromArgb(37, 99, 235);
 
            /// <summary>
            /// 鼠标悬停状态背景色(默认:深蓝色加深 #1D4ED8)
            /// </summary>
            [Category("自定义样式")]
            [Description("鼠标悬停时的背景色")]
            public Color HoverBackColor { get; set; } = Color.FromArgb(29, 78, 216);
 
            /// <summary>
            /// 鼠标点击状态背景色(默认:深蓝色更深 #1E40AF)
            /// </summary>
            [Category("自定义样式")]
            [Description("鼠标点击时的背景色")]
            public Color ClickBackColor { get; set; } = Color.FromArgb(30, 64, 175);
 
            /// <summary>
            /// 正常状态文字色(默认:白色)
            /// </summary>
            [Category("自定义样式")]
            [Description("按钮正常状态的文字颜色")]
            public Color NormalForeColor { get; set; } = Color.White;
 
            /// <summary>
            /// 鼠标悬停状态文字色(默认:白色)
            /// </summary>
            [Category("自定义样式")]
            [Description("鼠标悬停时的文字颜色")]
            public Color HoverForeColor { get; set; } = Color.White;
 
            /// <summary>
            /// 鼠标点击状态文字色(默认:白色)
            /// </summary>
            [Category("自定义样式")]
            [Description("鼠标点击时的文字颜色")]
            public Color ClickForeColor { get; set; } = Color.White;
 
            /// <summary>
            /// 按钮边框颜色(默认:透明,不显示边框)
            /// </summary>
            [Category("自定义样式")]
            [Description("按钮边框颜色")]
            public Color BorderColor { get; set; } = Color.Transparent;
 
            /// <summary>
            /// 按钮边框宽度(默认:1px)
            /// </summary>
            [Category("自定义样式")]
            [Description("按钮边框宽度")]
            public int BorderWidth { get; set; } = 1;
 
            /// <summary>
            /// 按钮文字(默认:"按钮")
            /// </summary>
            [Category("自定义样式")]
            [Description("按钮显示的文字")]
            public new string Text { get; set; } = "按钮";
 
            /// <summary>
            /// 按钮文字字体(默认:宋体 12号 加粗)
            /// </summary>
            [Category("自定义样式")]
            [Description("按钮文字字体")]
            public new Font Font { get; set; } = new Font("宋体", 12F, FontStyle.Bold);
 
            /// <summary>
            /// 是否强制半圆(默认:true,4个角为标准半圆;false时使用自定义半径)
            /// </summary>
            [Category("自定义样式")]
            [Description("是否强制4个角为半圆(true=半圆,false=自定义半径)")]
            public bool ForceSemiCircle { get; set; } = true;
 
            /// <summary>
            /// 自定义圆角半径(仅ForceSemiCircle=false时生效)
            /// </summary>
            [Category("自定义样式")]
            [Description("自定义圆角半径(仅ForceSemiCircle=false时生效)")]
            public int CustomCornerRadius { get; set; } = 6;
            #endregion
 
            #region 私有字段
            // 当前按钮状态(正常/悬停/点击)
            private ButtonState _currentState = ButtonState.Normal;
            // 按钮状态枚举
            private enum ButtonState
            {
                Normal,
                Hover,
                Click
            }
            #endregion
 
            public SemiCircleButton()
            {
                // 基础设置(.NET 4.8兼容)
                SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
                DoubleBuffered = true; // 双缓冲防止闪烁
                Size = new Size(120, 40); // 默认大小(宽度>高度,确保半圆效果)
                Cursor = Cursors.Hand; // 鼠标悬停时显示手型
 
                // 绑定鼠标事件(C# 7.3兼容)
                MouseEnter += SemiCircleButton_MouseEnter;
                MouseLeave += SemiCircleButton_MouseLeave;
                MouseDown += SemiCircleButton_MouseDown;
                MouseUp += SemiCircleButton_MouseUp;
                Paint += SemiCircleButton_Paint;
            }
 
            #region 鼠标事件处理(状态切换)
            private void SemiCircleButton_MouseEnter(object sender, EventArgs e)
            {
                if (_currentState != ButtonState.Click)
                {
                    _currentState = ButtonState.Hover;
                    Invalidate();
                }
            }
 
            private void SemiCircleButton_MouseLeave(object sender, EventArgs e)
            {
                _currentState = ButtonState.Normal;
                Invalidate();
            }
 
            private void SemiCircleButton_MouseDown(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    _currentState = ButtonState.Click;
                    Invalidate();
                }
            }
 
            private void SemiCircleButton_MouseUp(object sender, MouseEventArgs e)
            {
                _currentState = ClientRectangle.Contains(e.Location) ? ButtonState.Hover : ButtonState.Normal;
                Invalidate();
            }
            #endregion
 
            #region 核心修改:半圆角绘制逻辑
            private void SemiCircleButton_Paint(object sender, PaintEventArgs e)
            {
                var g = e.Graphics;
                g.SmoothingMode = SmoothingMode.AntiAlias; // 抗锯齿(半圆更平滑)
                g.Clear(Parent?.BackColor ?? Color.Transparent);
 
                // 1. 获取当前状态的颜色
                (Color backColor, Color foreColor) = GetCurrentStateColors();
 
                // 2. 计算半圆半径(核心:半径=按钮高度的1/2,且不超过宽度的1/2)
                int radius = CalculateSemiCircleRadius();
 
                // 3. 绘制半圆背景
                using (var brush = new SolidBrush(backColor))
                using (var path = CreateSemiCirclePath(ClientRectangle, radius))
                {
                    g.FillPath(brush, path);
                }
 
                // 4. 绘制边框(如果边框颜色非透明)
                if (BorderColor != Color.Transparent && BorderWidth > 0)
                {
                    using (var pen = new Pen(BorderColor, BorderWidth))
                    using (var path = CreateSemiCirclePath(GetBorderRectangle(radius), radius - BorderWidth / 2))
                    {
                        g.DrawPath(pen, path);
                    }
                }
 
                // 5. 绘制居中文字
                using (var brush = new SolidBrush(foreColor))
                {
                    var stringFormat = new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center,
                        FormatFlags = StringFormatFlags.NoWrap
                    };
                    g.DrawString(Text, Font, brush, ClientRectangle, stringFormat);
                }
            }
 
            /// <summary>
            /// 计算半圆半径(核心逻辑)
            /// </summary>
            private int CalculateSemiCircleRadius()
            {
                if (!ForceSemiCircle)
                    return Math.Max(0, CustomCornerRadius); // 非强制半圆时使用自定义半径
 
                // 强制半圆:半径=按钮高度的1/2,且不超过宽度的1/2(避免左右半圆超出控件)
                int heightHalf = ClientRectangle.Height / 2;
                int widthHalf = ClientRectangle.Width / 2;
                return Math.Min(heightHalf, widthHalf);
            }
 
            /// <summary>
            /// 创建半圆角路径(4个角均为半圆)
            /// </summary>
            private GraphicsPath CreateSemiCirclePath(Rectangle rect, int radius)
            {
                var path = new GraphicsPath();
                radius = Math.Max(0, radius);
 
                if (radius == 0)
                {
                    path.AddRectangle(rect);
                    return path;
                }
 
                // 关键:4个角均为半圆(圆弧角度=90度,半径=控件高度的1/2)
                // 左上角半圆:圆心(rect.X+radius, rect.Y+radius),半径radius,角度180→270
                path.AddArc(rect.X, rect.Y, radius * 2, radius * 2, 180, 90);
                // 右上角半圆:圆心(rect.Right-radius, rect.Y+radius),半径radius,角度270→360
                path.AddArc(rect.Right - radius * 2, rect.Y, radius * 2, radius * 2, 270, 90);
                // 右下角半圆:圆心(rect.Right-radius, rect.Bottom-radius),半径radius,角度0→90
                path.AddArc(rect.Right - radius * 2, rect.Bottom - radius * 2, radius * 2, radius * 2, 0, 90);
                // 左下角半圆:圆心(rect.X+radius, rect.Bottom-radius),半径radius,角度90→180
                path.AddArc(rect.X, rect.Bottom - radius * 2, radius * 2, radius * 2, 90, 90);
 
                path.CloseAllFigures();
                return path;
            }
 
            /// <summary>
            /// 获取边框绘制区域(避免边框超出半圆范围)
            /// </summary>
            private Rectangle GetBorderRectangle(int radius)
            {
                int offset = BorderWidth / 2;
                // 边框区域向内偏移,且左右预留半圆半径空间
                // 修复后(正确代码)
                return new Rectangle(
                    ClientRectangle.X + offset,
                    ClientRectangle.Y + offset,
                    ClientRectangle.Width - BorderWidth,
                    ClientRectangle.Height - BorderWidth
                );
            }
            #endregion
 
            #region 辅助方法与重写事件
            /// <summary>
            /// 根据当前状态获取颜色
            /// </summary>
            private (Color BackColor, Color ForeColor) GetCurrentStateColors()
            {
                switch (_currentState)
                {
                    case ButtonState.Hover:
                        return (HoverBackColor, HoverForeColor);
                    case ButtonState.Click:
                        return (ClickBackColor, ClickForeColor);
                    default:
                        return (NormalBackColor, NormalForeColor);
                }
            }
 
            /// <summary>
            /// 控件大小变化时重新计算半圆半径
            /// </summary>
            protected override void OnResize(EventArgs e)
            {
                base.OnResize(e);
                Invalidate(); // 刷新半圆效果
            }
 
            /// <summary>
            /// 禁用状态颜色处理
            /// </summary>
            protected override void OnEnabledChanged(EventArgs e)
            {
                base.OnEnabledChanged(e);
                if (!Enabled)
                {
                    NormalBackColor = DarkenColor(NormalBackColor, 0.5f);
                    HoverBackColor = DarkenColor(HoverBackColor, 0.5f);
                    ClickBackColor = DarkenColor(ClickBackColor, 0.5f);
                }
                Invalidate();
            }
 
            /// <summary>
            /// 颜色变暗(禁用状态使用)
            /// </summary>
            private Color DarkenColor(Color color, float factor)
            {
                return Color.FromArgb(
                    color.A,
                    (int)(color.R * (1 - factor)),
                    (int)(color.G * (1 - factor)),
                    (int)(color.B * (1 - factor))
                );
            }
 
            /// <summary>
            /// 暴露点击事件(兼容标准用法)
            /// </summary>
            protected override void OnClick(EventArgs e)
            {
                base.OnClick(e);
            }
            #endregion
        }
    }
 


 // 圆形按钮(宽=高=60px)
            var circleBtn = new SemiCircleButton
            {
                Text = "开始",
                Size = new Size(300, 100), // 宽=高→圆形
                Location = new Point(80, 80),
                ForceSemiCircle = true,
                NormalBackColor = Color.FromArgb(239, 68, 68),
                HoverBackColor = Color.FromArgb(220, 38, 38),
                ClickBackColor = Color.FromArgb(185, 28, 28),
                BorderColor = Color.White,
                BorderWidth = 2,
                Font = new Font("宋体", 11F, FontStyle.Bold)
            };
 
            circleBtn.Click += (s, args) => MessageBox.Show("圆形按钮被点击!");
            this.Controls.Add(circleBtn);
            return;

效果

wingform 圆型按钮 可调节

wingform 圆型按钮 可调节

© 版权声明

相关文章

暂无评论

none
暂无评论...