当前位置:首页 > 人生 > 作品墙 > 正文内容

蚂蚁线AntLine 控件调用文档

作品墙1周前 (10-23)


命名空间:CConUI
继承:System.Windows.Forms.Control
定位:虚线蚂蚁线选区控件,支持鼠标穿透、8 向拉伸、整体移动、滚轮缩放、边界限制、固定大小模式,以及与父控件(如 PictureBox)联动。

依赖:CConPlus.Enum.RectOffset(struct,含 Left / Top / Right / Bottom 四个 int 字段)
本控件使用 using static CConPlus.Enum;,因此属性签名里出现 RectOffset 时实际类型为 CConPlus.Enum.RectOffset。


一、作用

常用于图片裁剪、截图工具、屏幕取色、局部放大等场景,在父控件上叠加一层“虚线选框”,具备如下特性:

  • 鼠标穿透:未命中选框时鼠标消息穿透到父控件,不干扰父控件(如图片拖动)

  • 8 向拉伸:N / S / W / E / NW / NE / SW / SE 八个方向拉伸缩放

  • 整体移动:命中内部拖动即可移动

  • 新建选框:在空白处按住 Ctrl + 左键拖动即可创建新选框

  • 滚轮缩放:以鼠标位置为中心等比缩放(最小 4×4)

  • 边界限制:默认限制在父控件客户区内,可用 RestrictRect 向内偏移

  • 固定大小模式:为 true 时不能拉伸、碰边只平移不裁剪

  • 蚂蚁线动画:虚线持续滚动


二、快速上手

using CConUI;

// 1. 创建蚂蚁线控件
AntLine ant = new AntLine();

// 2. 添加到父容器(通常是 PictureBox 或 Panel),并 Dock 填充
ant.Parent = pictureBox1;
ant.Dock = DockStyle.Fill;

// 3. 设置选框矩形(坐标相对 AntLine 客户区,即父控件客户区)
ant.AntRect = new Rectangle(50, 50, 200, 150);

// 4. 显示(默认为 true,但如果之前被 Hide 过需要恢复)
ant.Visible = true;

// 5. 监听矩形变化
ant.AntRectChanged += (s, e) =>
{
    Console.WriteLine("矩形变化:" + ant.AntRect);
};

坐标说明:AntRect 使用的是 AntLine 控件客户区坐标系。由于 AntLine 通常以 Dock = Fill 铺满父控件(如 PictureBox),因此其客户区坐标与父控件客户区坐标重合——这也是它被称为“贴合父控件选框”的原因。


三、构造函数

public AntLine()

项目说明
参数无
作用初始化蚂蚁线控件
初始样式SupportsTransparentBackColor | UserPaint | AllPaintingInWmPaint | OptimizedDoubleBuffer,BackColor = Transparent
焦点Selectable = false,TabStop = false(不抢占父控件键盘/滚轮事件)
定时器创建并启动动画 Timer,间隔 AnimationInterval = 100,每次让虚线偏移 +1 像素
初始矩形Rectangle.Empty(不显示,需自行赋值 AntRect)
初始外观Color1 = White、Color2 = Black、DashLength = 4、DashGap = 4、AntLineSize = 1
初始行为WheelZoomEnabled = true、RestrictRect = null、FixedSize = false
var ant = new AntLine
{
    Parent = pictureBox1,
    Dock = DockStyle.Fill,
    AntRect = new Rectangle(100, 100, 300, 200)
};

四、公开属性

4.1 public int AnimationInterval

项目说明
类型int(毫秒)
默认100(源码字段 _antSpeed = 100)
CategoryCCon_外观
作用蚂蚁线动画刷新间隔。数值越小,虚线滚动越快
取值范围仅当 value > 10 时才被接受(≤10 会被忽略)
副作用若定时器已创建,会立即更新其 Interval,无需重启

⚠ 属性描述文本写的是“默认50”,但源码中字段初值为 100。请以实际代码为准。

ant.AnimationInterval = 50;    // 更快的虚线动画
ant.AnimationInterval = 200;   // 更慢的虚线动画

4.2 public Rectangle AntRect

项目说明
类型Rectangle
默认Rectangle.Empty(不显示)
Category(未标注,即设计器分类默认 杂项)
坐标AntLine 控件客户区坐标系(通常等同父控件客户区)
作用蚂蚁线的矩形区域。设置时会自动应用边界限制(见 RestrictRect / FixedSize)
副作用① 如果值与旧值不同:Invalidate() 重绘;② 触发 AntRectChanged;③ 若宽或高变化 → 触发 AntRectResized;
④ 否则若坐标变化 → 触发 AntRectMoved
设空传入 Rectangle.Empty 时不做 ApplyRestriction,直接生效(用于隐藏选框)
ant.AntRect = new Rectangle(50, 50, 200, 150);   // 显示选框
ant.AntRect = Rectangle.Empty;                    // 隐藏选框(不绘制)

4.3 public Color Color1

项目说明
类型Color
默认Color.White
CategoryCCon_外观
编辑器ArgbColorEditor(支持 ARGB 可视化选择)
作用蚂蚁线的主色(第一组虚线颜色)
ant.Color1 = Color.Lime;

4.4 public Color Color2

项目说明
类型Color
默认Color.Black
CategoryCCon_外观
编辑器ArgbColorEditor
作用蚂蚁线的副色(第二组虚线颜色),与主色交错形成经典“蚂蚁线”效果
ant.Color1 = Color.White;
ant.Color2 = Color.Black;    // 经典黑白蚂蚁线

4.5 public int DashLength

项目说明
类型int(像素)
默认4
CategoryCCon_外观
作用虚线实线段的长度(像素)
取值范围仅当 value > 0 时才被接受
ant.DashLength = 6;

4.6 public int DashGap

项目说明
类型int(像素)
默认4
CategoryCCon_外观
作用虚线间隔段的长度(像素)
取值范围仅当 value > 0 时才被接受
ant.DashGap = 6;

4.7 public int AntLineSize

项目说明
类型int(像素)
默认1
CategoryCCon_外观
作用线条粗细;同时影响边缘命中容差(_hitTolerance + AntLineSize / 2)
取值范围仅当 value > 0 时才被接受
ant.AntLineSize = 2;

4.8 public bool WheelZoomEnabled

项目说明
类型bool
默认true
CategoryCCon_控制
作用是否允许鼠标滚轮缩放选框大小。仅在鼠标命中选框(内部或边缘容差内)时才生效
ant.WheelZoomEnabled = false;   // 禁用滚轮缩放

4.9 public RectOffset? RestrictRect

项目说明
类型CConPlus.Enum.RectOffset?(可空 struct)
默认null(限制区域 = 父控件客户区)
CategoryCCon_控制
作用在父控件客户区基础上向内偏移,作为选框的合法区域。
例如 new RectOffset(10, 10, 10, 10) 表示四面各向内 10 像素
副作用若当前已有非空 AntRect,赋值后会立即执行一次 AntRect = ApplyRestriction(AntRect) 强制回到新边界内
特殊场景若偏移量过大,导致有效区域为空(Width ≤ 0 或 Height ≤ 0),ApplyRestriction 返回 Rectangle.Empty,选框被清空
using CConPlus.Enum;

// 在父控件四周各向内偏移 10 像素作为可移动区域
ant.RestrictRect = new RectOffset(10, 10, 10, 10);

// 取消限制
ant.RestrictRect = null;

RectOffset 是 struct,字段为 Left、Top、Right、Bottom(顺序按源码 new Rectangle(parent.X + L, parent.Y + T, W - L - R, H - T - B) 的解释)。

4.10 public bool FixedSize

项目说明
类型bool
默认false
CategoryCCon_控制
作用是否固定选框大小。
true:① 边缘命中被强制降级为 Move(无法拉伸);② 边界碰撞时只平移,不裁剪宽高;
false:正常 8 向拉伸;碰边裁剪缩小
副作用赋值后立即 Invalidate()
ant.FixedSize = true;    // 锁定大小,只能移动

五、公开事件

5.1 public event EventHandler AntRectChanged

项目说明
参数EventHandler(e 为 EventArgs.Empty)
触发时机AntRect 值发生实际变化时最先触发(无论移动还是缩放)
触发顺序先 AntRectChanged → 再视情况触发 AntRectResized 或 AntRectMoved
ant.AntRectChanged += (s, e) =>
{
    // 获取当前选框
    Rectangle r = ((AntLine)s).AntRect;
    label1.Text = $"选区:{r.X},{r.Y} 尺寸 {r.Width}×{r.Height}";
};

5.2 public event EventHandler AntRectResized

项目说明
CategoryCCon_事件
触发时机当 AntRect 的 Width 或 Height 发生变化时触发
(包括:边缘拉伸、滚轮缩放、RestrictRect 导致裁剪、外部赋值改变大小)
不触发情况只是移动位置(宽高不变)时不触发
ant.AntRectResized += (s, e) =>
{
    Rectangle r = ((AntLine)s).AntRect;
    Console.WriteLine("尺寸变化 → " + r.Width + " × " + r.Height);
};

5.3 public event EventHandler AntRectMoved

项目说明
CategoryCCon_事件
触发时机当 AntRect 的宽高不变,但 X 或 Y 发生变化时触发
(包括:整体拖动、外部赋值改坐标、FixedSize 碰边平移)
不触发情况宽高同时改变时(此时走 AntRectResized)不触发
ant.AntRectMoved += (s, e) =>
{
    Rectangle r = ((AntLine)s).AntRect;
    Console.WriteLine("位置变化 → " + r.X + "," + r.Y);
};

事件互斥逻辑(按源码):

if (宽或高变了) 触发 AntRectResized;
else if (X 或 Y 变了) 触发 AntRectMoved;

因此一次赋值只会触发两者之一,而 AntRectChanged 每次都会触发(只要值变化)。若同时改变位置和大小,只会触发 AntRectResized。


六、公开方法

本控件没有自定义 public 方法。
其功能全部通过属性赋值(AntRect)和鼠标/键盘交互完成。
继承的公开方法(如 Invalidate、Focus、BringToFront 等)来自 Control,可按需使用。


七、鼠标交互一览

操作条件效果
鼠标悬停内部选框内光标变为 SizeAll,表示可拖动
悬停边缘/角选框边缘或角容差内光标变为对应拉伸样式(SizeNS / SizeWE / SizeNWSE / SizeNESW)
悬停空白处 + 按 Ctrl选框外光标变为 Cross,提示可新建
左键按下内部命中内部进入 Move 拖动模式,捕获鼠标
左键按边缘/角命中边缘/角进入对应方向的拉伸模式
左键空白处 + Ctrl选框外 + Ctrl进入 Create 新建模式,选框从无到有
拖动过程中拖动/拉伸/新建实时更新 AntRect,自动应用边界限制
左键抬起拖动状态中结束拖动、释放捕获
滚轮向上(Delta>0)WheelZoomEnabled=true 且命中选框以鼠标位置为中心放大 1.1 倍(最小 4×4)
滚轮向下(Delta<0)同上缩小 1/1.1 倍
鼠标未命中选框(WndProc 拦截 WM_NCHITTEST)返回 HTTRANSPARENT,鼠标消息穿透到父控件

边缘命中容差:tol = _hitTolerance(6) + AntLineSize / 2,即在选框边缘外 tol 像素内都算命中边缘。


八、边界限制逻辑

模式属性逻辑
默认边界RestrictRect = null允许区域 = Parent.ClientRectangle
自定义边距RestrictRect = RectOffset(L, T, R, B)允许区域 = Parent.ClientRectangle 向内偏移 L/T/R/B 像素
普通模式裁剪FixedSize = false调用 Rectangle.Intersect(rect, bounds),超出边界的部分会被直接裁剪(宽高变小)
固定大小平移FixedSize = true碰边时只平移 X/Y 使其回到边界内,宽高保持不变;只有选框比边界还大时才强制截断
// 限制到父控件四周向内 10 像素区域,且框大小锁定
ant.RestrictRect = new RectOffset(10, 10, 10, 10);
ant.FixedSize = true;
ant.AntRect = new Rectangle(50, 50, 200, 150);  // 若碰边则自动平移,不变形

九、蚂蚁线绘制细节

项目说明
主色/副色Color1 与 Color2 两遍绘制,形成双色交错虚线
虚线段DashPattern = {DashLength / AntLineSize, DashGap / AntLineSize}(因 GDI+ 相对单位是线宽倍数)
相位交错Color2 的 DashOffset 比 Color1 多一个 DashLength / AntLineSize,实现无缝交错
动画每 AnimationInterval 毫秒让 _dashOffset +1 像素(取模),触发 Invalidate(_antRect) 局部重绘
防裁剪PenAlignment.Inset 且绘制矩形宽高 −1,防止线宽较大时右侧/下侧被裁切
空矩形AntRect == Rectangle.Empty 时 OnPaint 直接返回,定时器也不重绘

十、鼠标穿透机制

本控件重写了 WndProc,处理 Windows 消息 WM_NCHITTEST (0x0084):

  1. 取鼠标屏幕坐标转成控件客户区坐标;

  2. 若 HitTest(p) == HitArea.None(未命中内部、边缘或容差区域),返回 HTTRANSPARENT (-1),让父控件接收该鼠标消息;

  3. 否则正常返回,由本控件处理。

因此在 PictureBox(MouseEnabled = true)上叠加 AntLine 后:

  • 鼠标在选框内部或边缘时,滚轮/拖动被 AntLine 消费(拖选框);

  • 鼠标在选框外的空白处时,滚轮/拖动会穿透到 PictureBox(缩放/拖动图片)。


十一、完整使用示例

示例 1:最简选框

var ant = new AntLine
{
    Parent = pictureBox1,
    Dock = DockStyle.Fill,
    AntRect = new Rectangle(50, 50, 200, 150)
};

ant.AntRectChanged += (s, e) => Console.WriteLine(ant.AntRect);

示例 2:与 PictureBox 联动裁剪

// 假设已经有:
//   PictureBox pb(MouseEnabled = true)
//   AntLine ant(Dock=Fill 到 pb)

ant.AntRect = new Rectangle(100, 100, 300, 200);

// 通过按钮触发裁剪
btnCrop.Click += (s, e) =>
{
    using (Bitmap bmp = pb.GetImageInRectangle(ant.AntRect))
    {
        if (bmp != null)
        {
            bmp.Save("cropped.png", System.Drawing.Imaging.ImageFormat.Png);
            MessageBox.Show("已保存 cropped.png");
        }
    }
};

由于 AntLine 以 Dock=Fill 填充 PictureBox,AntRect 使用的坐标与 PictureBox 客户区坐标一致,可以直接传给 pb.GetImageInRectangle(...)。

示例 3:固定大小 + 边距约束

using CConPlus.Enum;

var ant = new AntLine
{
    Parent = pictureBox1,
    Dock = DockStyle.Fill,
    FixedSize = true,                                 // 锁定大小,只能移动
    RestrictRect = new RectOffset(20, 20, 20, 20),    // 距离父控件四边各 20 像素
    AntRect = new Rectangle(100, 100, 200, 150),
    Color1 = Color.Lime,
    Color2 = Color.Black,
    DashLength = 6,
    DashGap = 4,
    AntLineSize = 2
};

示例 4:关闭滚轮缩放(不与父控件争抢滚轮)

var ant = new AntLine
{
    Parent = pictureBox1,
    Dock = DockStyle.Fill,
    WheelZoomEnabled = false,   // 不使用滚轮缩放
    AntRect = new Rectangle(50, 50, 200, 150)
};

示例 5:用事件分别处理移动与缩放

ant.AntRectMoved += (s, e) =>
{
    Rectangle r = ((AntLine)s).AntRect;
    lblPos.Text = $"位置:({r.X}, {r.Y})";
};

ant.AntRectResized += (s, e) =>
{
    Rectangle r = ((AntLine)s).AntRect;
    lblSize.Text = $"尺寸:{r.Width} × {r.Height}";
};

示例 6:程序化创建/清空选框

// 显示一个从 (100,100) 到 (300,250) 的选框
ant.AntRect = new Rectangle(100, 100, 200, 150);

// 清空(隐藏选框、停止绘制)
ant.AntRect = Rectangle.Empty;

十二、公开成员速查表

成员类型说明
AntLine()构造函数创建控件并启动动画定时器
AntRect属性选框矩形;赋值自动应用边界限制并触发事件
Color1属性(ARGB)主色(默认白)
Color2属性(ARGB)副色(默认黑)
DashLength属性实线长度(像素)
DashGap属性间隔长度(像素)
AntLineSize属性线条粗细(像素)
AnimationInterval属性动画刷新间隔(毫秒),>10 生效
WheelZoomEnabled属性是否允许滚轮缩放
RestrictRect属性(可空 struct)边界向内偏移
FixedSize属性锁定大小(禁止拉伸,碰边只平移)
AntRectChanged事件矩形任意变化时触发
AntRectResized事件宽高变化时触发
AntRectMoved事件位置变化(宽高不变)时触发

十三、注意事项

  1. 坐标是 AntLine 客户区坐标。AntLine 应 Dock = Fill 在父控件(如 PictureBox)上,此时 AntRect 坐标 = 父控件客户区坐标。

  2. 默认不显示。构造时 AntRect = Rectangle.Empty,必须显式赋值才会绘制。可设置 ant.AntRect = Rectangle.Empty 来隐藏。

  3. 事件互斥:AntRectResized 和 AntRectMoved 不会同时触发。同时改位置和大小时只触发 AntRectResized。若需要“任意变化”用 AntRectChanged。

  4. 赋相同值不触发事件。AntRect 的 setter 会先对比 _antRect != newRect,相同则直接返回,避免重复重绘和事件。

  5. 范围限制:AnimationInterval 必须 >10;DashLength / DashGap / AntLineSize 必须 >0,否则被忽略。

  6. 滚轮缩放最小尺寸为 4×4,无法再缩小。

  7. 滚轮缩放只对命中的选框生效。要禁用滚轮交互(让滚轮完全穿透到父控件)请设 WheelZoomEnabled = false;即使 true,未命中选框时 WndProc 也会返回 HTTRANSPARENT,让父控件处理。

  8. 固定大小模式无法拉伸:FixedSize=true 时,命中边缘也会被当成 Move,无法拉伸。但滚轮缩放仍有效(代码里 OnMouseWheel 未检查 FixedSize,只用了 ApplyFixedSizeRestriction,因此滚轮仍能改变大小,但会保持“碰边平移”的语义)。如需完全锁定,需额外设置 WheelZoomEnabled=false。

  9. RectOffset 是 struct,可空。设 null 表示只受父控件客户区限制;设值表示在父控件基础上再向内偏移。

  10. 偏移量过大导致有效区域为空时,ApplyRestriction 返回 Rectangle.Empty,选框会被清空。

  11. 构造时立即启动定时器。即使 AntRect = Empty,定时器仍每 AnimationInterval 触发一次(只是不重绘)。对性能敏感的场景可考虑在隐藏时不创建控件(Controls.Remove),或在 Dispose 时自动停止(代码已处理)。

  12. AntLine 不抢占焦点(Selectable = false、TabStop = false),不会影响父控件的键盘和滚轮事件处理。

  13. AntRectChanged / AntRectResized / AntRectMoved 在内部鼠标拖动、滚轮缩放、外部赋值时都会触发,不需要额外订阅鼠标事件即可得知矩形变化。

  14. 与 PictureBox 配合时,由于 AntLine 在 PictureBox.Controls 中,作为子控件会随 PictureBox 的图片拖动而移动吗?不会——AntLine 的 Parent 是 PictureBox,Dock=Fill 是相对父控件的客户端区域固定的。图片的 zoom/offset 只影响 PictureBox 自身 OnPaint 的绘制,不影响子控件位置。
    因此 AntRect 的坐标是“**屏幕空间(父控件可视空间)**”,配合 PictureBox.GetImageInRectangle(antRect) 时,控件内部会自动完成反变换,得到当前视口该区域显示的原图内容。


转载请注明出处。

本文链接:http://www.pythonopen.com/?id=7972

相关文章

已经实现的一些算法

编码CConA1是一种可复原的编码算法,用于将文本或字节转换为纯字母。可用于文件名混淆,避免因包含违...

横向滚动条HScrollBar 控件调用文档

命名空间:CConUI继承:System.Windows.Forms.Control版本:基于所提供...

纵向滚动条VScrollBar 控件调用文档

命名空间:CConUI继承:System.Windows.Forms.Control版本:基于所提供...

菜单MenuItem 与 ContextMenu 控件调用文档

命名空间:CConUI依赖:System.Windows.Forms、System.Drawing、...

图片框PictureBox 控件调用文档

命名空间:CConUI继承:System.Windows.Forms.Control定位:自绘图片框...