当前位置: 首页 > article >正文

C#控件开发2—流动管道

目录

  • 1.定义属性
  • 2.画布重绘
  • 3. 图形方法
  • 4.关键代码
  • End

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

三步

  1. 定义属性
  2. 画布重绘
  3. 图形方法

1.定义属性

  • 管道的(两端转向、样式、边沿颜色、中间颜色、激活)
  • 流动条的(速度、长度、宽度、间隙、颜色)
//属性示例:按照示例添加以上各种属性
private float moveSpeed = 0.3f;
[Browsable(true)]
[Category("布局_G")]
[Description("流动条速度,负数为反向")]  //属性说明
public float MoveSpeed
{
    get { return moveSpeed; }
    set
    {
        this.moveSpeed = value;
        this.Invalidate();  //重绘
    }
}

2.画布重绘

  • 水平管道分为左、中、右三部分;垂直管道分为上、中、下;分别绘制(两端不动朝向的情况)
  • 设置画布质量、渐近线比例、颜色
  • 画椭圆:PaintEllipse(图形、笔、绘制路径…)
  • 画矩形:PaintRectangle(图形、笔、绘制路径…)
  • 画虚线(流动条):AddArc(添加椭圆)、AddLine(添加直线)
  • 运用两个画椭圆、画矩形的方法,见3
#region 画布

//字段
private Graphics g;   //GPI绘图
private Pen p;  //画笔
private float startOffset = 0; //短划线起始位置
private Timer myTimer;

protected override void OnPaint(PaintEventArgs e)
{
    //画布质量
    g = e.Graphics;
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
    ColorBlend colorBlend = new ColorBlend();  //渐变色设置

    //渐近线比例、颜色
    colorBlend.Positions = new float[] { 0.0f, 0.5f, 1.0f };
    colorBlend.Colors = new Color[] { this.pipeColorEdge, this.pipeColorCenter, this.pipeColorEdge };

    //画笔初始化
    this.p = new Pen(this.pipeColorBorder, 1.0f);

    //管道绘制(水平)
    if (this.pipeStyle == PipeStyle.Horizontal)
    {
        //矩形画刷
        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));
        }

        //绘制流动条
        if (isActive)
        {
            //流动条路径
            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);
        }
    }
    //管道绘制(垂直)
    else
    {
        //矩形画刷
        LinearGradientBrush linearGradientBrush2 = new LinearGradientBrush(new Point(0, 0), new Point(this.Width, 0), pipeColorEdge, pipeColorEdge);
        linearGradientBrush2.InterpolationColors = colorBlend;

        //绘制上部分
        switch (this.pipeTurnLeft)
        {
            case PipeTurn.Left:
                this.PaintEllipse(g, colorBlend, p, new Rectangle(-this.Width-1, 0, this.Width * 2, this.Width * 2), 270.0f, 90.0f);
                break;
            case PipeTurn.Right:
                this.PaintEllipse(g, colorBlend, p, new Rectangle(0, 0, this.Width * 2, this.Width * 2), 180.0f, 90.0f);
                break;
            default:
                this.PaintRectangle(g, linearGradientBrush2, p, new Rectangle(0, -1, this.Width, this.Width+1));
                break;
        }

        //绘制下部分
        switch (this.pipeTurnRight)
        {
            case PipeTurn.Left:
                this.PaintEllipse(g, colorBlend, p, new Rectangle(-this.Width-1, this.Height - this.Width * 2, this.Width * 2, this.Width * 2), 0.0f, 90.0f);
                break;
            case PipeTurn.Right:
                this.PaintEllipse(g, colorBlend, p, new Rectangle(0, this.Height - this.Width * 2, this.Width * 2, this.Width * 2), 90f, 90.0f);
                break;
            default:
                this.PaintRectangle(g, linearGradientBrush2, p, new Rectangle(0, this.Height - this.Width, this.Width, this.Width));
                break;
        }

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

        //绘制流动条
        if (isActive)
        {
            //流动条路径
            GraphicsPath path = new GraphicsPath();

            //虚线路径—上边
            switch (this.pipeTurnLeft)
            {
                case PipeTurn.Left:
                    path.AddArc(new Rectangle(-this.Width / 2-1, this.Width / 2, this.Width, this.Width), 270.0f, 88.0f);
                    break;
                case PipeTurn.Right:
                    path.AddArc(new Rectangle(this.Width / 2, this.Width / 2, this.Width, this.Width), 271.0f, -90.0f);
                    break;
                default:
                    path.AddLine(this.Width / 2, -1, this.Width / 2, this.Width);
                    break;
            }

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

            //虚线路径—下边
            switch (this.pipeTurnRight)
            {
                case PipeTurn.Left:
                    path.AddArc(new Rectangle(-this.Width / 2-1, this.Height - this.Width * 3 / 2-1, this.Width, this.Width), 0f, 91.0f);
                    break;
                case PipeTurn.Right:
                    path.AddArc(new Rectangle(this.Width / 2, this.Height  - this.Width * 3 / 2, this.Width, this.Width), 180.0f, -90.0f);
                    break;
                default:
                    path.AddLine(this.Width / 2, this.Height - this.Width, this.Width / 2, this.Height );
                    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);
        }
    }
}

#endregion

3. 图形方法

  • 画渐变色半圆的方法:PaintEllipse
  • 画渐变色矩形的方法:PaintRectangle
#region 画管道的方法
/// <summary>
/// 画渐变色半圆的方法
/// </summary>
/// <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);
}

/// <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;
    }
}

#endregion

4.关键代码


  1. 绘制的椭圆、线——代码释义

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);

绘制的椭圆、线(Rectangle)<x,y【圆切矩形相对于控件原点<左上角>的坐标】,宽,高,开始角度,扫描角度>理解了就好画了


  1. 可以流动的关键要素
---构造函数
  
     //流动条流动速度(刷新速度)
     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


End


http://www.kler.cn/a/457590.html

相关文章:

  • unity学习5:创建一个自己的3D项目
  • typescript安装后仍然不能使用tsc,如何解决
  • 二、CSS基础
  • ESP32 I2S音频总线学习笔记(一):初识I2S通信与配置基础
  • 安卓11 SysteUI添加按钮以及下拉状态栏的色温调节按钮
  • 使用CSS 和 JavaScript 实现鼠标悬停时图片放大、缩小和抖动
  • 小猫咪抽奖系统源码1.11(有卡密功能)
  • 【潜意识Java】探寻Java子类构造器的神秘面纱与独特魅力,深度学习子类构造器特点
  • 4. 指针和动态内存
  • Pytorch | 利用PC-I-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
  • 【13】Selenium+Python UI自动化测试 集成日志(某积载系统实例-07)
  • 【学习笔记】ChatGPT原理与应用开发——基础科普
  • No.29 笔记 | CTF 学习干货
  • C++ 设计模式:策略模式(Strategy Pattern)
  • 「Mac畅玩鸿蒙与硬件48」UI互动应用篇25 - 简易购物车功能实现
  • 【Spring】基于注解的Spring容器配置——@Scope注解
  • 如何通过采购管理系统提升供应链协同效率?
  • Android Bluetooth 问题:BluetoothAdapter enable 方法失效
  • 【2025最新计算机毕业设计】基于SpringBoot的网上服装商城系统(高质量项目,可定制)【提供源码+答辩PPT+文档+项目部署】
  • 一起来看--红黑树
  • TVS二极管选型【EMC】
  • 从0入门自主空中机器人-2-2【无人机硬件选型-PX4篇】
  • 每日一题 354. 俄罗斯套娃信封问题
  • 2025年阿斯利康GATE笔试测评春招校招社招笔试入职测评行测题型解读揭秘
  • MATLAB 车牌自动识别系统设计 SVM支持向量机方法 车牌识别
  • 代码随想录第60天