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

C#自定义控件—流动管道的更多相关文章

  1. NodeJS Stream 五:双工流

    双工流就是同时实现了 Readable 和 Writable 的流,即可以作为上游生产数据,又可以作为下游消费数据,这样可以处于数据流动管道的中间部分,即 rs.pipe(rws1).pipe(rws ...

  2. nodeJS之流stream

    前面的话 当内存中无法一次装下需要处理的数据时,或者一边读取一边处理更加高效时,我们就需要用到数据流.NodeJS中通过各种Stream来提供对数据流的操作.本文将详细说明NodeJS中的流strea ...

  3. 基于react-app搭建react-router+redux项目

    前言 总括: 本文采用react+redux+react-router+less+es6+webpack,以实现一个简易备忘录(todolist)为例尽可能全面的讲述使用react全家桶实现一个完整应 ...

  4. 1.3 React 组件

    1.3.1 React 组件介绍 在 React 中组件是第一元素,是 React 的基础,一个 React 应用就是基于 React 组件的组合而成.前面的 JSX 练习过后,大家应该对 React ...

  5. Web 组态运用之用户数据 ARPU 分析图

    前言 作为企业的发展,通过运营的有效管理,增加收入.降低成本,取得更好的经济效益,是核心所在,在电信企业同样如此.电信企业的利润大体上是由业务收入和成本决定的,而收入和成本又可进一步分别分解表达为不同 ...

  6. 极简 Node.js 入门 - 4.5 双工流

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  7. (五十五)c#Winform自定义控件-管道

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  8. OpenFOAM——不对称突变管道中的低雷诺数流动

    本算例来自<ANSYS Fluid Dynamics Verification Manual>中的VMFL064: Low Reynolds Number Flow in a Channe ...

  9. (五十八)c#Winform自定义控件-管道阀门(工业)

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  10. 基于HTML5实现3D监控应用流动效果

    http://www.hightopo.com/guide/guide/core/lighting/examples/example_flowing.html 流动效果在3D领域有着广泛的应用场景,如 ...

随机推荐

  1. welcome to chifan-duck's blog

    博主简介 截至至 2024 博主事一名初二学生. 为什么开博客园 因为博主是一名 Oier. 博客内容 OI 知识(科技)的普及 & 题解 为什么叫 chifan-duck ? 原本博主再各大 ...

  2. windows中运行nicegui官网内容

    内容受到bilibili视频nicegui官网访问不了?教你本地部署文档,我写python终于有界面启发,其余部分由chatgpt协助生成. 1. 在本地新建目录如 nicegui_web 2. 从g ...

  3. Solo 开发者周刊 (第8期):Claude公司再度上新产品,成交额将超73亿美元

    这里会整合 Solo 社区每周推广内容.产品模块或活动投稿,每周五发布.在这期周刊中,我们将深入探讨开源软件产品的开发旅程,分享来自一线独立开发者的经验和见解.本杂志开源,欢迎投稿. 好文推荐 Cla ...

  4. Elasticsearch tp5使用

    下载elassticsearch和kibana的网址:https://www.elastic.co/cn/downloads/?elektra=home&store=hero 下载Elasti ...

  5. Centos7 安装 rabbitmq-server-3.7.7 图文教程

    下载 rabbitmq-server wget https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.7/rabbitmq-server-3. ...

  6. char字符_C

    字符的表示  字符类型由单引号' '包围,字符串由双引号" "包围. //正确的写法 char a = '1'; char b = '$'; char c = 'X'; char ...

  7. Nginx 工作原理简介

    在了解Nginx工作原理之前,我们先来了解下几个基本的概念 以及常见的I/O模型. 基本概念 同步:就是指调用方发起一个调用,在没有得到调用结果之前,该调用不返回.换句话说,也就是调用方发起一个调用后 ...

  8. Python 按分类权重(区间)随机获取分类样本

    按分类权重(区间)随机获取分类样本 By:授客 QQ:1033553122 开发环境 win 10 python 3.6.5 需求 活动抽奖,参与抽奖产品有iphone, 华为,小米,魅族,vivo, ...

  9. UE5 打不开

    在游戏开发中,出现了UE打不开的情况 初步推测,新增了接口Attacker, 而我们的DefaultPawn可能一下子实现了两个接口造成的 而这两个接口都在一个插件里,一个是c++实现的,一个是蓝图实 ...

  10. nodejs的服务器,用ffmpeg推流

    http://m.zhizuobiao.com/node/node-19061200018/ ffmpeg -list_devices true -f dshow -i dummyffmpeg -f ...