170 lines
5.4 KiB
C#
170 lines
5.4 KiB
C#
/***************************************************
|
|
* CircleButton 2.0 · Red badge with built-in number
|
|
* Author : Gong Yuchao (2017-08-16), rev 2025-07-17
|
|
***************************************************/
|
|
using Lskj.Business;
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
|
|
namespace Lskj.Control
|
|
{
|
|
[DefaultEvent(nameof(Click))]
|
|
public partial class CircleButton : Button
|
|
{
|
|
/* ───────── 可调属性 ───────── */
|
|
|
|
private int _radius = 18 / 2; // 直径 18px
|
|
[Category("布局"), Description("圆点半径(px)")]
|
|
public int Radius
|
|
{
|
|
get => _radius;
|
|
set { _radius = Math.Max(4, value); SyncSize(); }
|
|
}
|
|
|
|
private int _number;
|
|
[Category("数据"), Description("角标数字(>99 显示 99)")]
|
|
public int Number
|
|
{
|
|
get => _number;
|
|
set { _number = Math.Max(0, value); Invalidate(); }
|
|
}
|
|
|
|
[Category("外观"), Description("普通状态图(可省略)")]
|
|
public Image ImageNormal
|
|
{
|
|
get => _imgNormal;
|
|
set { _imgNormal = value; if (!_hover) BackgroundImage = value; }
|
|
}
|
|
private Image _imgNormal;
|
|
|
|
[Category("外观"), Description("悬停状态图(可省略)")]
|
|
public Image ImageHover { get; set; }
|
|
|
|
[Category("外观"), Description("边框颜色(透明=无)")]
|
|
public Color BorderColor { get; set; } = Color.Transparent;
|
|
|
|
[Category("外观"), Description("边框粗细(px)")]
|
|
public float BorderThickness { get; set; } = 1f;
|
|
|
|
/* ───────── 状态 ───────── */
|
|
private bool _hover;
|
|
|
|
/* ───────── ctor ───────── */
|
|
public CircleButton()
|
|
{
|
|
SetStyle(ControlStyles.AllPaintingInWmPaint |
|
|
ControlStyles.UserPaint |
|
|
ControlStyles.OptimizedDoubleBuffer, true);
|
|
|
|
FlatStyle = FlatStyle.Flat;
|
|
FlatAppearance.BorderSize = 0;
|
|
BackColor = Color.Red;
|
|
ForeColor = Color.White;
|
|
|
|
SyncSize();
|
|
|
|
MouseEnter += (_, __) => SetHover(true);
|
|
MouseLeave += (_, __) => SetHover(false);
|
|
}
|
|
|
|
/* ───────── 重绘 ───────── */
|
|
protected override void OnResize(EventArgs e)
|
|
{
|
|
base.OnResize(e);
|
|
UpdateRegion();
|
|
}
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
base.OnPaint(e);
|
|
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
|
|
|
// ① 画圆填充
|
|
using (SolidBrush br = new SolidBrush(BackColor))
|
|
{
|
|
e.Graphics.FillEllipse(br, 0, 0, Width, Height);
|
|
}
|
|
|
|
// ② 画边框(可选)
|
|
if (BorderColor.A > 0 && BorderThickness > 0)
|
|
{
|
|
using (Pen pen = new Pen(BorderColor, BorderThickness))
|
|
{
|
|
Rectangle rc = new Rectangle(
|
|
(int)(BorderThickness / 2),
|
|
(int)(BorderThickness / 2),
|
|
Width - (int)BorderThickness,
|
|
Height - (int)BorderThickness);
|
|
e.Graphics.DrawEllipse(pen, rc);
|
|
}
|
|
}
|
|
|
|
// ③ 绘制数字
|
|
if (_number > 0)
|
|
{
|
|
string txt = _number > 99 ? "99" : _number.ToString();
|
|
using (SolidBrush fb = new SolidBrush(ForeColor))
|
|
using (StringFormat sf = new StringFormat
|
|
{
|
|
Alignment = StringAlignment.Center,
|
|
LineAlignment = StringAlignment.Center
|
|
})
|
|
{
|
|
e.Graphics.DrawString(txt, Font, fb,
|
|
new RectangleF(0, 0, Width, Height), sf);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ───────── 私有助手 ───────── */
|
|
private void SetHover(bool hover)
|
|
{
|
|
if (_hover == hover) return;
|
|
_hover = hover;
|
|
BackgroundImage = hover && ImageHover != null ? ImageHover : _imgNormal;
|
|
}
|
|
|
|
private void SyncSize()
|
|
{
|
|
Width = Height = _radius * 2;
|
|
UpdateRegion();
|
|
Invalidate();
|
|
}
|
|
|
|
private void UpdateRegion()
|
|
{
|
|
try
|
|
{
|
|
GraphicsPath gp = new GraphicsPath();
|
|
gp.AddEllipse(0, 0, Width, Height);
|
|
Region?.Dispose();
|
|
Region = new Region(gp);
|
|
}
|
|
catch (Exception ex) { Debug.WriteLine(ex); }
|
|
}
|
|
|
|
/* 隐藏 Size(设计器防误改) */
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public new Size Size
|
|
{
|
|
get => base.Size;
|
|
set => base.Size = value;
|
|
}
|
|
public void SetMenuNum(int num)
|
|
{
|
|
if (SystemInfo.Instance.DisableShowNotify || num < 1)
|
|
{
|
|
this.Visible = false;
|
|
return;
|
|
}
|
|
this.Number = num;
|
|
this.Visible = true;
|
|
}
|
|
}
|
|
}
|