前两天有人问用.NET怎么做类似于心电图的图像控件。我以前也从来没做过,但是感觉应该不是很困难,关键是要知道从哪开始下手。所以当时只是讲了下我的初步想法。
1.心电图显示的是线,而线则是由多个点组成,所以做这个效果实际上就是画点。
2.要画点,首先就需要设置参考坐标系,然后根据指定坐标来画点。
3.静态的点画好之后就要实现动态的效果了,也就是随着时间的推移,将所有的点往一个横向方向上移动,然后在最后面空出地方再补充上新的点。不过这里要注意的是,我们看到的仅仅只是显示区域的点,对于已经移出视野的那些点就可以抛弃了,不然越积越多,内存就要爆了。
昨天晚上没什么事,就想自己动手实践一下,看看理论与实际之间是否存在很大的差距。
首先,存放这么多个点需要一个容器,由于显示区域的宽度并没有固定,所以这个容器的容量应该是动态的,比如List
基于以上三个原因,我选择了从Queue
public class P
{
public int X { get ; set ; }
public int Y { get ; set ; }
}
对于P类,在真正使用的时候,可以对它的功能进行扩展,增加颜色等属性,使图像看起来更加丰富多彩。
创建好点的类,再创建PQueue类。
public class PQueue : Queue < P >
{
// 队列的最大容量
public int MaxCount { get ; set ; }
// 队列是否已装满
private bool isFull = false ;
public PQueue( int max)
{
MaxCount = max;
}
// 替换父类的Enqueue方法
new public void Enqueue(P item)
{
if (Count == MaxCount)
{
if ( ! isFull)
isFull = true ;
else
{
// 平移所有点, 图像开始动起来
foreach (P p in this )
p.X = p.X - 1 ;
}
}
base .Enqueue(item);
// 在添加新元素时弹出超过MaxCount的元素
while (Count > MaxCount)
Dequeue();
}
}
下面就要开始画图了,不过我没有选择直接操作PictureBox,而是单独建了个类,这样使用起来更加方便。
public class Img
{
private PQueue pQueue; // 要显示的点的队列
public int Width { get ; set ; } // 显示区域的宽度
public int Height { get ; set ; } // 显示区域的高度
public Color BackColor { get ; set ; } // 背景色
public Color PColor { get ; set ; } // 显示的点的颜色
public Image Image { get ; private set ; } // 显示的图像
public Img( int width, int height, Color backcolor, Color pcolor)
{
// 设定属性的初始值
Width = width;
Height = height;
pQueue = new PQueue(Width);
BackColor = backcolor;
PColor = pcolor;
Image = new Bitmap(Width, Height);
}
///
/// 画图
///
/// 要画的点的Y值,它是不变的, 而X值是要随着时间变化的
public void Draw( int pheight)
{
// 默认的坐标原点是左上角点, 为了好看, 这里将点翻转了一下
P p = new P(){X = pQueue.Count - 1 , Y = Height - pheight + 1 };
pQueue.Enqueue(p);
Graphics g = Graphics.FromImage(Image);
g.Clear(BackColor);
using (Pen pen = new Pen(PColor))
{
foreach (P p1 in pQueue)
{
Point point1 = new Point(p1.X, p1.Y);
// 一个像素点太小,把它加长一点就能看得更清楚了
Point point2 = new Point(p1.X, p1.Y + 3 );
g.DrawLine(pen, point1, point2);
}
}
g.Dispose();
}
}
画图的功能已经做好了,剩下的工作就是检验了。在使用以下代码前,现在窗体上放个PictureBox控件,命名为pic,宽度和高度都设为50.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load( object sender, EventArgs e)
{
img = new Img(pic.Width, pic.Height, Color.Black, Color.White);
System.Timers.Timer timer = new System.Timers.Timer( 50 );
timer.Enabled = true ;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
}
private Img img;
private int num = 20 ;
private int i = 1 ;
void timer_Elapsed( object sender, System.Timers.ElapsedEventArgs e)
{
img.Draw(num);
pic.Image = img.Image;
num = num + i;
if ( 40 == num)
i = - 1 ;
if ( 10 == num)
i = 1 ;
}
}
运行一下,最后可以看到一条运动的波浪线。以上代码仅仅只是实现了最简单的动画效果,其实只要在改造一下,就可以弄成像迅雷等下载工具的悬浮窗的速度显示效果了。
注:以上代码需要以下引用命名空间:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;