首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

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

编程知识
2024年09月02日 22:05

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;
      }
  }
  • 管道的绘制(渐变色半圆)
/// <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);
}
  • 流动条的绘制(用笔的虚线)
//画虚线,关键用笔和路径来画
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

From:https://www.cnblogs.com/guoenshuo/p/18391637
本文地址: http://shuzixingkong.net/article/1677
0评论
提交 加载更多评论
其他文章 使用kamailio进行分机注册及互拨
操作系统版本:Debian 12.5_x64 kamailio版本:5.8.2 kamailio作为专业的SIP服务器,可承担注册服务器的角色。今天记录下kamailio作为注册服务器,承接分机注册,并实现相互拨打的过程。 我将从以下几个方面展开: 模块配置 分机账号添加 无rtp代理的分机互拨 带
使用kamailio进行分机注册及互拨 使用kamailio进行分机注册及互拨 使用kamailio进行分机注册及互拨
呵,老板不过如此,SQL还是得看我
2018年7月,大三暑假进行时,时间过得飞快,我到这边实习都已经一个月了。 我在没工作之前,我老是觉得生产项目的代码跟我平时自学练的会有很大的区别。 以为生产项目代码啥的都会规范很多,比如在接口上会做很多安全性的工作(自学练的时候确实学到的类似的案例),代码设计上会有很多设计模式的应用。 但实际上,
呵,老板不过如此,SQL还是得看我 呵,老板不过如此,SQL还是得看我 呵,老板不过如此,SQL还是得看我
C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与视野拓宽。 欢迎投稿,推荐或自荐优质文章/项目/学习资源等。每周
C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31) C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31) C#/.NET/.NET Core技术前沿周刊 | 第 3 期(2024年8.26-8.31)
一场 Kafka CRC 异常引发的血案
一、问题概述 客户的生产环境突然在近期间歇式的收到了Kafka CRC的相关异常,异常内容如下 Record batch for partition skywalking-traces-0 at offset 292107075 is invalid, cause: Record is corrup
一场 Kafka CRC 异常引发的血案 一场 Kafka CRC 异常引发的血案 一场 Kafka CRC 异常引发的血案
全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法
在 Python 中,内置类型的行为是通过一组特殊的“魔法方法”来实现的,这些魔法方法以双下划线开头和结尾,比如 init 和 str,你可以通过重写这些魔法方法来定制或扩展内置类型的行为。
全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法 全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法 全网最适合入门的面向对象编程教程:44 Python内置函数与魔法方法-重写内置类型的魔法方法
解密Prompt系列37. RAG之前置决策何时联网的多种策略
前置判断模型回答是否需要联网,之前介绍了自我矛盾和自我拒绝者两个方案。这一章我们再补充几种基于微调,模型回答置信度和小模型代理回答的方案。
解密Prompt系列37. RAG之前置决策何时联网的多种策略 解密Prompt系列37. RAG之前置决策何时联网的多种策略 解密Prompt系列37. RAG之前置决策何时联网的多种策略
数据库中查询含有某个emoji表情的行数据
数据库中查询含有某个emoji表情的行数据 MySQL的情况 代码如下 ​ create table tt6(id int, name varchar(800)); insert into tt6 select 1, &#39;121&#128522;33&#39;; insert into tt6
数据库中查询含有某个emoji表情的行数据 数据库中查询含有某个emoji表情的行数据 数据库中查询含有某个emoji表情的行数据
省钱的开源项目「GitHub 热点速览」
本期,我从上周的热门开源项目中挑选了 5 个既省钱又省事,还好玩的开源项目。 首先,推荐的是省钱的电动汽车智能充电管理平台 evcc,它可以根据分时电价智能安排电动车充电时间,从而降低电费,如果你家还有太阳能充电和储能设备,evcc 更能最大限度地利用电能,让你的充电成本降到最低。说到省事,开源的
省钱的开源项目「GitHub 热点速览」 省钱的开源项目「GitHub 热点速览」 省钱的开源项目「GitHub 热点速览」