C#自定义控件—流动管道
C#用户控件之流动管道
如何绘制一个动态的流动管道(FlowPipe)?

分两步绘制
- 定义属性;
- 画布重绘;
主要技能:
- 管道的绘制(渐变色矩形)
/// <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#自定义控件—流动管道的更多相关文章
- NodeJS Stream 五:双工流
双工流就是同时实现了 Readable 和 Writable 的流,即可以作为上游生产数据,又可以作为下游消费数据,这样可以处于数据流动管道的中间部分,即 rs.pipe(rws1).pipe(rws ...
- nodeJS之流stream
前面的话 当内存中无法一次装下需要处理的数据时,或者一边读取一边处理更加高效时,我们就需要用到数据流.NodeJS中通过各种Stream来提供对数据流的操作.本文将详细说明NodeJS中的流strea ...
- 基于react-app搭建react-router+redux项目
前言 总括: 本文采用react+redux+react-router+less+es6+webpack,以实现一个简易备忘录(todolist)为例尽可能全面的讲述使用react全家桶实现一个完整应 ...
- 1.3 React 组件
1.3.1 React 组件介绍 在 React 中组件是第一元素,是 React 的基础,一个 React 应用就是基于 React 组件的组合而成.前面的 JSX 练习过后,大家应该对 React ...
- Web 组态运用之用户数据 ARPU 分析图
前言 作为企业的发展,通过运营的有效管理,增加收入.降低成本,取得更好的经济效益,是核心所在,在电信企业同样如此.电信企业的利润大体上是由业务收入和成本决定的,而收入和成本又可进一步分别分解表达为不同 ...
- 极简 Node.js 入门 - 4.5 双工流
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- (五十五)c#Winform自定义控件-管道
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- OpenFOAM——不对称突变管道中的低雷诺数流动
本算例来自<ANSYS Fluid Dynamics Verification Manual>中的VMFL064: Low Reynolds Number Flow in a Channe ...
- (五十八)c#Winform自定义控件-管道阀门(工业)
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- 基于HTML5实现3D监控应用流动效果
http://www.hightopo.com/guide/guide/core/lighting/examples/example_flowing.html 流动效果在3D领域有着广泛的应用场景,如 ...
随机推荐
- MinIO使用记录
探索MinIO:高性能.分布式对象存储解决方案 注:本文除代码外多数为AI生成 最近因为有项目需要换成Amazon S3的云存储,所以把之前做过的minio部分做一个记录,后面也会把基于这版改造的S3 ...
- react懒加载,减少首屏加载时间
最近在写一个react-ant-admin的集成框架用于快速搭载中后台项目.其中遇到很多问题,最重要的应该是访问速度了.我就想 react 可不可以和 vue 一样用路由懒加载来减少首页渲染所花费的时 ...
- Python 潮流周刊第 2 季完结了,分享几项总结
我订阅了很多的周刊/Newsletter,但是发现它们都有一个共同的毛病:就是缺乏对往期内容的整理,它们很少会对内容数据作统计分析,更没有将内容整理成合集的习惯. 在自己开始连载周刊后,我就想别开生面 ...
- Curve 进入 CNCF Sandbox,完善统一云原生开源存储拼图
2022 年 6 月 15 日,云原生计算基金会 (CNCF) 宣布,分布式存储系统 Curve 被正式接纳为 CNCF 沙箱(Sandbox)项目.Curve 由网易数帆开源,提供块存储和文件存储能 ...
- 要想业务中台建得快,最好用Service Mesh来带
中国企业数字化转型进入深水区,业务中台及下一代微服务Service Mesh(服务网格)被越来越多的人关注,本文结合网易轻舟微服务Service Mesh实践,解析业务中台为什么需要Service M ...
- Java实现快速快速排序算法
算法简介 快速排序(Quick Sort) 是由冒泡排序改进而得的.在冒泡排序过程中,只对相邻的两个记录进行比较,因此每次交换两个相邻记录时只能消除一个逆序.如果能通过两个(不相邻)记录的一次交换直接 ...
- 在Python中使用SWCNN去除水印
在Python中使用SWCNN去除水印 说明 首次发表日期:2024-07-17 SWCNN Github官方仓库: https://github.com/hellloxiaotian/SWCNN S ...
- 【楔子】单细胞测序-最佳的分析Pipeline
作者:starlitnightly 日期:2023.07.14 !!! note 楔子 从事单细胞分析也有一段时间了,国内大部分中文教程都是使用R语言进行分析,使用Python的还比较少,或者是直译s ...
- python+selenium基础之XPATH定位(第一篇)
世界上最远的距离大概就是明明看到一个页面元素站在那里,但是我却定位不到!! selenium定位元素的方法有很多种,像是通过id.name.class_name.tag_name.link_text等 ...
- 基于动态数据源的SAAS系统(SpringBoot+MybaitsPlus+Durid)
一.什么是SAAS系统 SAAS全称 Software as a Service,软件即服务.本人接触SAAS也在近两年:在我的理解,SAAS不是特指某种系统,它是提供某类产品的系统服务平台,让第三方 ...