C#自定义控件—流动管道

C#用户控件之流动管道

如何绘制一个动态的流动管道(FlowPipe)?

分两步绘制

  1. 定义属性;
  2. 画布重绘;

主要技能:

  • 管道的绘制(渐变色矩形)

    复制代码
    /// <summary>
    /// 画渐变色矩形的方法
    /// </summary>
    /// <param name="g">画布</param>
    /// <param name="brush">画刷</param>
    /// <param name="pen">笔</param>
    /// <param name="rectangle">矩形</param>
    private void PaintRectangle(Graphics g, Brush brush, Pen pen, Rectangle rectangle)
    {
        //填充矩形
        g.FillRectangle(brush, rectangle);
    
        switch (this.pipeStyle)
        {
            case PipeStyle.Horizontal:
                g.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X + rectangle.Width, rectangle.Y);
                g.DrawLine(pen, rectangle.X, rectangle.Y + rectangle.Height - 1, rectangle.X + rectangle.Width, rectangle.Height);
                break;
            case PipeStyle.Vertical:
                g.DrawLine(pen, rectangle.X, rectangle.Y, rectangle.X, rectangle.Y + rectangle.Height);
                g.DrawLine(pen, rectangle.X + rectangle.Width - 1, rectangle.Y, rectangle.X + rectangle.Width - 1, rectangle.Height);
                break;
            default:
                break;
        }
    }
  • 管道的绘制(渐变色半圆)

    ///


    /// 画渐变色半圆的方法
    ///

    /// <param name="g">画布</param>
    /// <param name="colorBlend"></param>
    /// <param name="p"></param>
    /// <param name="rect"></param>
    /// <param name="startAngle"></param>
    /// <param name="sweepAngle"></param>
    private void PaintEllipse(Graphics g, ColorBlend colorBlend, Pen p, Rectangle rect, float startAngle, float sweepAngle)
    {
    //第一步:创建GPI路径
    GraphicsPath path = new GraphicsPath();
    path.AddEllipse(rect);

    复制代码
      //第二步:渐变色填充
      PathGradientBrush brush = new PathGradientBrush(path);
      brush.CenterPoint = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
      brush.InterpolationColors = colorBlend;
    
      //第三步:绘制管道
      g.FillPie(brush, rect, startAngle, sweepAngle);
    
      //第四步:绘制边线
      g.DrawArc(p, rect, startAngle, sweepAngle);

    }

  • 流动条的绘制(用笔的虚线)

    //画虚线,关键用笔和路径来画
    Pen pen = new Pen(this.flowColor, this.flowWidth);
    pen.DashStyle = DashStyle.Custom;
    pen.DashPattern = new float[]
    {
    flowLength,flowLengthGap
    };
    pen.DashOffset = this.startOffset;
    g.DrawPath(pen, path);

    //流动条路径
    GraphicsPath path = new GraphicsPath();

    //虚线路径---左边、中间、右边
    switch (this.pipeTurnLeft)
    {
    case PipeTurn.Up:
    path.AddArc(new Rectangle(this.Height / 2, this.Height / 2 * (-1) -1, this.Height, this.Height), 181.0f, -91.0f);
    break;
    case PipeTurn.Down:
    path.AddArc(new Rectangle(this.Height / 2, this.Height / 2, this.Height, this.Height), 180.0f, 90.0f);
    break;
    default:
    path.AddLine(-1, this.Height / 2, this.Height+1, this.Height / 2);
    break;
    }

  • 关键理解:绘制的椭圆、线(Rectangle)<x,y【圆切矩形相对于控件原点<左上角>的坐标】,宽,高,开始角度,扫描角度>理解了就好画了
    path.AddArc(new Rectangle(this.Height / 2, this.Height / 2, this.Height, this.Height), 180.0f, 90.0f);
    path.AddLine(-1, this.Height / 2, this.Height+1, this.Height / 2);

  • 可以流动的关键要素

    复制代码
       //流动条流动速度(刷新速度)
       this.myTimer = new Timer();
       myTimer.Interval = 50;
       this.myTimer.Tick += MyTimer_Tick; ;

    }

    #region 定时循环
    private void MyTimer_Tick(object sender, EventArgs e)
    {
    this.startOffset = this.startOffset - this.moveSpeed;

    复制代码
       if (this.startOffset > this.flowLength + this.flowLengthGap || this.startOffset < (this.flowLength + this.flowLengthGap) * (-1))
       { this.startOffset = 0; }
       this.Invalidate();

    }

    #endregion

1.定义属性

  • 管道的(两端转向、样式、边沿颜色、中间颜色、激活)

  • 流动条的(速度、长度、宽度、间隙、颜色)

    //属性示例:按照示例添加以上各种属性
    private float moveSpeed = 0.3f;
    [Browsable(true)]
    [Category("布局_G")]
    [Description("流动条速度,负数为反向")] //属性说明
    public float MoveSpeed
    {
    get { return moveSpeed; }
    set
    {
    this.moveSpeed = value;
    this.Invalidate(); //重绘
    }
    }

2.画布重绘

复制代码
【管道分为左、中、右三部分。先画管道(矩形):左、中、右;再画流动条(虚线):左、中、右】
//矩形画刷
LinearGradientBrush linearGradientBrush = new LinearGradientBrush(new Point(0, 0), new Point(0, this.Height), pipeColorEdge, pipeColorEdge);
linearGradientBrush.InterpolationColors = colorBlend;

//绘制左部分
switch (this.pipeTurnLeft)
{
    case PipeTurn.Up:
        this.PaintEllipse(g, colorBlend, p, new Rectangle(0, this.Height * (-1)-1, this.Height * 2, this.Height * 2), 90.0f, 90.0f);
        break;
    case PipeTurn.Down:
        this.PaintEllipse(g, colorBlend, p, new Rectangle(0, 0, this.Height * 2, this.Height * 2), 180.0f, 90.0f);
        break;
    default:
        this.PaintRectangle(g, linearGradientBrush, p, new Rectangle(-1, 0, this.Height+1, this.Height));
        break;
}

//绘制右部分
switch (this.pipeTurnRight)
{
    case PipeTurn.Up:
        this.PaintEllipse(g, colorBlend, p, new Rectangle(this.Width - this.Height * 2, this.Height * (-1)-1, this.Height * 2, this.Height * 2), 0.0f, 90.0f);
        break;
    case PipeTurn.Down:
        this.PaintEllipse(g, colorBlend, p, new Rectangle(this.Width - this.Height * 2, 0, this.Height * 2, this.Height * 2), 270.0f, 90.0f);
        break;
    default:
        this.PaintRectangle(g, linearGradientBrush, p, new Rectangle(this.Width - this.Height, 0, this.Height, this.Height));
        break;
}

//绘制中间
if (this.Width > this.Height * 2)
{
    this.PaintRectangle(g, linearGradientBrush, p, new Rectangle(this.Height - 1, 0, this.Width - this.Height * 2 + 2, this.Height));
}

//流动条路径
GraphicsPath path = new GraphicsPath();

//虚线路径---左边
switch (this.pipeTurnLeft)
{
    case PipeTurn.Up:
        path.AddArc(new Rectangle(this.Height / 2, this.Height / 2 * (-1) -1, this.Height, this.Height), 181.0f, -91.0f);
        break;
    case PipeTurn.Down:
        path.AddArc(new Rectangle(this.Height / 2, this.Height / 2, this.Height, this.Height), 180.0f, 90.0f);
        break;
    default:
        path.AddLine(-1, this.Height / 2, this.Height+1, this.Height / 2);
        break;
}

//虚线路径---中间
if (this.Width > this.Height * 2)
{
    path.AddLine(this.Height, this.Height / 2, this.Width - this.Height -1, this.Height / 2);
}

//虚线路径---右边
switch (this.pipeTurnRight)
{
    case PipeTurn.Up:
        path.AddArc(new Rectangle(this.Width - 1 - this.Height * 3 / 2, -this.Height / 2-1 , this.Height, this.Height), 88f, -91.0f);
        break;
    case PipeTurn.Down:
        path.AddArc(new Rectangle(this.Width - 1 - this.Height * 3 / 2, this.Height / 2, this.Height, this.Height), 270.0f, 90.0f);
        break;
    default:
        path.AddLine(this.Width - this.Height, this.Height / 2, this.Width , this.Height / 2);
        break;
}

//画虚线,关键用笔和路径来
Pen pen = new Pen(this.flowColor, this.flowWidth);
pen.DashStyle = DashStyle.Custom;
pen.DashPattern = new float[]
{
    flowLength,flowLengthGap
};
pen.DashOffset = this.startOffset;
g.DrawPath(pen, path);

格式都是一样的,掌握关键代码,肝就对了。

End

相关推荐
神仙别闹6 分钟前
基于C#+SQL Server实现(Web)学生选课管理系统
前端·数据库·c#
向宇it1 小时前
【unity组件介绍】URP Decal Projector贴花投影器,将特定材质(贴花)投影到场景中的其他对象上。
游戏·3d·unity·c#·游戏引擎·材质
斯是 陋室10 小时前
在CentOS7.9服务器上安装.NET 8.0 SDK
运维·服务器·开发语言·c++·c#·云计算·.net
inwith12 小时前
C#语法基础总结(超级全面)(二)
开发语言·c#
ヾChen15 小时前
13届蓝桥杯省赛程序设计试题
物联网·学习·蓝桥杯·c#
我是唐青枫20 小时前
C#.NET 泛型详解
开发语言·c#·.net
Yasin Chen20 小时前
C# StringBuilder源码分析
开发语言·c#
格林威21 小时前
Baumer工业相机堡盟工业相机如何通过YoloV8模型实现人物识别(C#)
开发语言·人工智能·数码相机·yolo·计算机视觉·c#
Rabbb1 天前
C# JSON 反序列化时,忽略转换失败的属性 JTokenSafeToExtensions
后端·c#·json
三目条件1 天前
C#将类属性保存到Ini文件方法(利用拓展方法,反射方式获取到分组名和属性名称属性值)
java·开发语言·c#