From 3fe559694156ed5726c6324f1e83a3fe0cba4cbf Mon Sep 17 00:00:00 2001
From: zhubanghao <58813184@qq.com>
Date: Tue, 20 Jan 2026 09:05:19 +0000
Subject: [PATCH] =?UTF-8?q?=F0=9F=98=BA=20=E6=96=B0=E5=A2=9E=20=E7=A4=BA?=
=?UTF-8?q?=E4=BE=8B=20BallTest=20=E6=82=AC=E6=B5=AE=E7=90=83=E7=AA=97?=
=?UTF-8?q?=E4=BD=93?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
AntdUI.sln | 9 +-
example/BallTest/BallLayeredForm.cs | 387 ++++++++++++++++++++++++++
example/BallTest/BallLayeredForm.resx | 120 ++++++++
example/BallTest/BallTest.csproj | 20 ++
example/BallTest/Program.cs | 26 ++
5 files changed, 561 insertions(+), 1 deletion(-)
create mode 100644 example/BallTest/BallLayeredForm.cs
create mode 100644 example/BallTest/BallLayeredForm.resx
create mode 100644 example/BallTest/BallTest.csproj
create mode 100644 example/BallTest/Program.cs
diff --git a/AntdUI.sln b/AntdUI.sln
index 77a03c95..8aa89b39 100644
--- a/AntdUI.sln
+++ b/AntdUI.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
-VisualStudioVersion = 18.1.11312.151 d18.0
+VisualStudioVersion = 18.1.11312.151
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{B9AB491E-DDF2-4E3D-97FA-622E36504B91}"
EndProject
@@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3762ED79-9
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphemeSplitterTest", "test\GraphemeSplitterTest\GraphemeSplitterTest.csproj", "{01ACFED0-8673-06F4-52A8-D45E69339517}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BallTest", "example\BallTest\BallTest.csproj", "{6EF92ED2-D4CF-A5F8-09EF-FDE92C580659}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -57,6 +59,10 @@ Global
{01ACFED0-8673-06F4-52A8-D45E69339517}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01ACFED0-8673-06F4-52A8-D45E69339517}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01ACFED0-8673-06F4-52A8-D45E69339517}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6EF92ED2-D4CF-A5F8-09EF-FDE92C580659}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6EF92ED2-D4CF-A5F8-09EF-FDE92C580659}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6EF92ED2-D4CF-A5F8-09EF-FDE92C580659}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6EF92ED2-D4CF-A5F8-09EF-FDE92C580659}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -69,6 +75,7 @@ Global
{94493153-4FF8-4F33-8589-D72A8563AF52} = {B9AB491E-DDF2-4E3D-97FA-622E36504B91}
{3A032088-E22D-BFA0-83BC-B0CD61CAD7BF} = {5243A57B-3E12-49E1-BA51-CBB5D786193F}
{01ACFED0-8673-06F4-52A8-D45E69339517} = {3762ED79-94BC-42B3-A024-E0F1F375BCEB}
+ {6EF92ED2-D4CF-A5F8-09EF-FDE92C580659} = {B9AB491E-DDF2-4E3D-97FA-622E36504B91}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6B151716-3D07-4DA4-8C4D-2D2BBE164EAA}
diff --git a/example/BallTest/BallLayeredForm.cs b/example/BallTest/BallLayeredForm.cs
new file mode 100644
index 00000000..0e810879
--- /dev/null
+++ b/example/BallTest/BallLayeredForm.cs
@@ -0,0 +1,387 @@
+using AntdUI;
+using System;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Windows.Forms;
+
+namespace BallTest
+{
+ public partial class BallLayeredForm : ILayeredFormOpacity
+ {
+ #region 属性
+ // 防误触阈值
+ private const int DRAG_THRESHOLD = 5;
+
+ // 拖动相关变量
+ private Point? dragStartPoint = null;
+ private bool isBeingDragged = false;
+ private bool isClick = false;
+
+ // 鼠标悬停状态
+ private bool isMouseOver = false;
+ ///
+ /// 菜单项列表 - 使用AntdUI控件
+ ///
+ private AntdUI.IContextMenuStripItem[] menuItems;
+ #region 颜色配置字段 - 封装颜色定义,便于自定义和修改
+
+ private Color _normalStartColor = Color.FromArgb(0, 128, 255); // 正常状态起始颜色
+ private Color _normalEndColor = Color.FromArgb(0, 75, 150); // 正常状态结束颜色
+ private Color _hoverStartColor = Color.FromArgb(0, 191, 255); // 悬停状态起始颜色
+ private Color _hoverEndColor = Color.FromArgb(0, 100, 200); // 悬停状态结束颜色
+ private Color _highlightColor1 = Color.White; // 主高光颜色
+ private int _highlightAlpha1 = 150; // 主高光透明度
+ private Color _highlightColor2 = Color.White; // 次高光颜色
+ private int _highlightAlpha2 = 100; // 次高光透明度
+ private Color _borderColor = Color.FromArgb(0, 50, 100); // 边框颜色
+ private int _borderAlpha = 120; // 边框透明度
+ private int _borderWidth = 2; // 边框宽度
+
+ // 颜色配置公共属性,便于外部自定义
+ // 添加DesignerSerializationVisibility特性以解决WFO1000警告
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public Color NormalStartColor
+ {
+ get => _normalStartColor;
+ set { _normalStartColor = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public Color NormalEndColor
+ {
+ get => _normalEndColor;
+ set { _normalEndColor = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public Color HoverStartColor
+ {
+ get => _hoverStartColor;
+ set { _hoverStartColor = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public Color HoverEndColor
+ {
+ get => _hoverEndColor;
+ set { _hoverEndColor = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public Color HighlightColor1
+ {
+ get => _highlightColor1;
+ set { _highlightColor1 = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public int HighlightAlpha1
+ {
+ get => _highlightAlpha1;
+ set { _highlightAlpha1 = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public Color HighlightColor2
+ {
+ get => _highlightColor2;
+ set { _highlightColor2 = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public int HighlightAlpha2
+ {
+ get => _highlightAlpha2;
+ set { _highlightAlpha2 = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public Color BorderColor
+ {
+ get => _borderColor;
+ set { _borderColor = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public int BorderAlpha
+ {
+ get => _borderAlpha;
+ set { _borderAlpha = value; Print(); }
+ }
+
+ [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
+ public int BorderWidth
+ {
+ get => _borderWidth;
+ set { _borderWidth = value; Print(); }
+ }
+
+ #endregion
+ #endregion
+
+ #region 构造相关的方法
+ public BallLayeredForm() : base(255)
+ {
+ // 设置默认大小和位置
+ int size = 200;
+ int x = Screen.PrimaryScreen.Bounds.Width / 2 - size / 2;
+ int y = Screen.PrimaryScreen.Bounds.Height / 2 - size / 2;
+
+ SetSize(size, size);
+ SetLocation(x, y);
+ // 同时设置Size和Location属性,确保窗体正确显示
+ Size = new Size(size, size);
+ Location = new Point(x, y);
+
+ // 设置为最顶层窗口,确保能看到
+ TopMost = true;
+
+ // 初始化菜单项
+ InitializeMenuItems();
+ }
+
+ public override bool UFocus => false;
+
+ public override string name => nameof(BallLayeredForm);
+
+ // 初始化菜单项
+ private void InitializeMenuItems()
+ {
+
+ string svg_back = "", svg_refresh = "", svg_save = "", svg_print = "", svg_laptop = "", svg_qr = "", svg_a = "", svg_fy = "", svg_add = "", svg_share = "", svg_about = "";
+
+ menuItems = new AntdUI.IContextMenuStripItem[]
+ {
+ new AntdUI.ContextMenuStripItem("返回", "Alt+向左键").SetIcon(svg_back),
+ new AntdUI.ContextMenuStripItem("刷新", "Ctrl+R").SetIcon(svg_refresh),
+ new AntdUI.ContextMenuStripItemDivider(),
+ new AntdUI.ContextMenuStripItem("另存为", "Ctrl+S").SetIcon(svg_save),
+ new AntdUI.ContextMenuStripItem("打印", "Ctrl+P").SetIcon(svg_print),
+ new AntdUI.ContextMenuStripItemDivider(),
+ new AntdUI.ContextMenuStripItem("发送标签页到你的设备").SetIcon(svg_laptop),
+ new AntdUI.ContextMenuStripItem("为此页面创建QR代码").SetIcon(svg_qr),
+ new AntdUI.ContextMenuStripItem("大声朗读", "Ctrl+Shift+U").SetIcon(svg_a),
+ new AntdUI.ContextMenuStripItem("翻译为 中文(简体)").SetIcon(svg_fy),
+ new AntdUI.ContextMenuStripItem("将页面添加到集锦").SetIcon(svg_add).SetSub(
+ new AntdUI.ContextMenuStripItem("返回", "Alt+向左键").SetIcon(svg_back).SetSub(
+ new AntdUI.ContextMenuStripItem("返回", "Alt+向左键").SetIcon(svg_back),
+ new AntdUI.ContextMenuStripItem("刷新", "Ctrl+R").SetIcon(svg_refresh),
+ new AntdUI.ContextMenuStripItemDivider(),
+ new AntdUI.ContextMenuStripItem("另存为", "Ctrl+S").SetIcon(svg_save),
+ new AntdUI.ContextMenuStripItem("打印", "Ctrl+P").SetIcon(svg_print)
+ ),
+ new AntdUI.ContextMenuStripItem("刷新", "Ctrl+R").SetIcon(svg_refresh),
+ new AntdUI.ContextMenuStripItemDivider(),
+ new AntdUI.ContextMenuStripItem("另存为", "Ctrl+S").SetIcon(svg_save),
+ new AntdUI.ContextMenuStripItem("打印", "Ctrl+P").SetIcon(svg_print)
+ ),
+ new AntdUI.ContextMenuStripItemDivider(),
+ new AntdUI.ContextMenuStripItem("共享").SetIcon(svg_share),
+ new AntdUI.ContextMenuStripItem("关于").SetIcon(svg_about)
+ };
+ }
+ #endregion
+
+ #region 鼠标相关事件
+ protected override void OnHandleCreated(EventArgs e)
+ {
+ base.OnHandleCreated(e);
+ // 窗口句柄创建后立即渲染
+ Print();
+ }
+
+ public override Bitmap? PrintBit()
+ {
+ // 获取目标区域大小
+ var rect = TargetRect;
+ var rectXY = TargetRectXY;
+
+ // 创建一个与目标区域大小相同的位图,使用32位ARGB格式
+ var bitmap = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+
+ using (var g = Graphics.FromImage(bitmap))
+ {
+ // 设置高质量绘图选项
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+ g.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ g.PixelOffsetMode = PixelOffsetMode.HighQuality;
+
+ // 清除背景(透明)
+ g.Clear(Color.Transparent);
+
+ // 绘制渐变圆球
+ int centerX = rect.Width / 2;
+ int centerY = rect.Height / 2;
+ int radius = Math.Min(centerX, centerY) - 10;
+
+ // 根据鼠标状态选择渐变颜色
+ Color startColor = isMouseOver ? _hoverStartColor : _normalStartColor;
+ Color endColor = isMouseOver ? _hoverEndColor : _normalEndColor;
+
+ // 使用线性渐变,从左上角到右下角
+ using (var gradientBrush = new LinearGradientBrush(
+ new Point(centerX - radius, centerY - radius),
+ new Point(centerX + radius, centerY + radius),
+ startColor,
+ endColor))
+ {
+ // 绘制圆形主体
+ g.FillEllipse(gradientBrush, centerX - radius, centerY - radius, radius * 2, radius * 2);
+
+ // 添加多层次高光,增强立体感
+ // 主高光:左上角明亮的白色椭圆形高光(参考图片2)
+ using (var highlightBrush1 = new SolidBrush(Color.FromArgb(_highlightAlpha1, _highlightColor1)))
+ {
+ int highlightWidth = radius * 3 / 2;
+ int highlightHeight = radius * 3 / 4;
+ g.FillEllipse(highlightBrush1,
+ centerX - highlightWidth / 2,
+ centerY - highlightHeight / 2 - radius / 6,
+ highlightWidth, highlightHeight);
+ }
+
+ // 次高光:中心位置的白色高亮区
+ using (var highlightBrush2 = new SolidBrush(Color.FromArgb(_highlightAlpha2, _highlightColor2)))
+ {
+ int centerHighlightSize = radius * 2 / 3;
+ g.FillEllipse(highlightBrush2,
+ centerX - centerHighlightSize / 2,
+ centerY - centerHighlightSize / 2,
+ centerHighlightSize, centerHighlightSize);
+ }
+
+ // 调整边框:使用深蓝色边框,更精致
+ using (var pen = new Pen(Color.FromArgb(_borderAlpha, _borderColor), _borderWidth))
+ {
+ g.DrawEllipse(pen, centerX - radius, centerY - radius, radius * 2, radius * 2);
+ }
+ }
+ }
+
+ return bitmap;
+ }
+
+ protected override void OnMouseEnter(EventArgs e)
+ {
+ isMouseOver = true;
+ Print();
+ base.OnMouseEnter(e);
+ }
+
+ protected override void OnMouseLeave(EventArgs e)
+ {
+ isMouseOver = false;
+ Print();
+ base.OnMouseLeave(e);
+ }
+
+ // 鼠标按下事件,开始拖动或显示右键菜单
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ base.OnMouseDown(e);
+ if (e.Button == MouseButtons.Left)
+ {
+ isClick = true;
+ dragStartPoint = e.Location;
+ // 更改光标样式
+ Cursor = Cursors.SizeAll;
+ }
+ else if (e.Button == MouseButtons.Right)
+ {
+ // 获取鼠标在屏幕上的位置
+ Point screenPos = PointToScreen(e.Location);
+
+ // 显示AntdUI右键菜单
+ var config = new AntdUI.ContextMenuStrip.Config(new AntdUI.Target(this), item =>
+ {
+ // 处理菜单项点击事件
+ //switch (item.Text)
+ //{
+ // case "返回":
+ // // 移动功能已通过拖动实现
+
+ // break;
+ // case "刷新":
+ // // IClose(true);
+ // break;
+ // case "关于":
+ // break;
+ //}
+ AntdUI.Notification.open(this, item.Text, "AntdUI 作者人不错", TAlignFrom.Top);
+ }, menuItems)
+ {
+ Location = screenPos, // 设置菜单位置为当前鼠标位置
+ TopMost = true
+ };
+ AntdUI.ContextMenuStrip.open(config);
+ }
+ }
+
+ // 鼠标移动事件,处理拖动
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ base.OnMouseMove(e);
+ // 处理拖动逻辑
+ if (dragStartPoint.HasValue)
+ {
+ int deltaX = e.X - dragStartPoint.Value.X;
+ int deltaY = e.Y - dragStartPoint.Value.Y;
+
+ // 检查是否超过防误触阈值
+ if (!isBeingDragged && (Math.Abs(deltaX) > DRAG_THRESHOLD || Math.Abs(deltaY) > DRAG_THRESHOLD))
+ {
+ isBeingDragged = true;
+ isClick = false;
+ }
+
+ if (isBeingDragged)
+ {
+ // 更新位置
+ var rect = TargetRect;
+ int newX = rect.X + deltaX;
+ int newY = rect.Y + deltaY;
+
+ // 设置新位置
+ SetLocation(newX, newY);
+ Location = new Point(newX, newY);
+
+ // 使用PrintCache优化拖动性能
+ PrintCache();
+ }
+ }
+ }
+
+ // 鼠标释放事件,结束拖动
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ base.OnMouseUp(e);
+
+ // 恢复默认光标
+ Cursor = DefaultCursor;
+
+ // 处理点击事件
+ if (isClick && !isBeingDragged)
+ {
+ // 左键点击关闭窗口
+ if (e.Button == MouseButtons.Left)
+ {
+ //IClose(true);
+ }
+ }
+
+ // 重置拖动状态
+ dragStartPoint = null;
+ isBeingDragged = false;
+ isClick = false;
+ }
+
+ protected override void OnMouseClick(MouseEventArgs e)
+ {
+ base.OnMouseClick(e);
+ // 右键点击事件已由ContextMenuStrip处理
+ }
+ #endregion
+ }
+
+
+}
\ No newline at end of file
diff --git a/example/BallTest/BallLayeredForm.resx b/example/BallTest/BallLayeredForm.resx
new file mode 100644
index 00000000..1af7de15
--- /dev/null
+++ b/example/BallTest/BallLayeredForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/example/BallTest/BallTest.csproj b/example/BallTest/BallTest.csproj
new file mode 100644
index 00000000..443cdc96
--- /dev/null
+++ b/example/BallTest/BallTest.csproj
@@ -0,0 +1,20 @@
+
+
+
+ WinExe
+ net8.0-windows
+ true
+ enable
+
+
+
+
+
+
+
+
+ Form
+
+
+
+
\ No newline at end of file
diff --git a/example/BallTest/Program.cs b/example/BallTest/Program.cs
new file mode 100644
index 00000000..d9977845
--- /dev/null
+++ b/example/BallTest/Program.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Windows.Forms;
+using AntdUI;
+
+namespace BallTest
+{
+ static class Program
+ {
+ ///
+ /// 应用程序的主入口点。
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+
+ // 创建并显示圆球窗体
+ var ballForm = new BallLayeredForm();
+ ballForm.Show();
+
+ // 运行应用程序消息循环
+ Application.Run();
+ }
+ }
+}
\ No newline at end of file