在做一个WinForm登录框时,突然想到,如果有黑客帝国中字符雨的特效做背景,那应该蛮Cool的,所以就有了如下代码,随意写的,有点乱。
public
partial
class
CharacterRain : Component
{
/**////
/// 必需的设计器变量。
///
private System.ComponentModel.IContainer components = null;
/**////
/// 清理所有正在使用的资源。
///
/// 如果应释放托管资源,为 true;否则为 false。
protected override void Dispose(bool disposing)
{
if (RainThread != null && RainThread.IsAlive)
Stop();
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
组件设计器生成的代码#region 组件设计器生成的代码
/**////
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
///
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
public CharacterRain()
{
Initialize();
InitializeComponent();
}
public CharacterRain(IContainer container)
{
Initialize();
container.Add(this);
InitializeComponent();
}
private object BMPLock = new object();
private Bitmap BMP;
private Graphics Graph;
private void Initialize()
{
this.DrawRainEvent = new EventHandler(CharacterRainPanel_DrawRainEvent);
OnPaint = new PaintEventHandler(ShowWindow_Paint);
}
private PaintEventHandler OnPaint;
private char[] CHARACTERS = { '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\\', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '|', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?' };
private static readonly Random Rand = new Random();
private Control _ShowWindow = null;
/**////
/// 获取、设置用于显示字符雨的窗口(或控件)
///
public Control ShowWindow
{
get { return _ShowWindow; }
set
{
if (_ShowWindow != null)
_ShowWindow.Paint -= OnPaint;
_ShowWindow = value;
if (_ShowWindow != null)
_ShowWindow.Paint += OnPaint;
}
}
void ShowWindow_Paint(object sender, PaintEventArgs e)
{
//Paint();
if (BMP != null)
{
lock (BMPLock)
{
//e.Graphics.Clear(_ShowWindow.BackColor);
try
{
e.Graphics.DrawImage(BMP, 0, 0);
}
catch
{
}
}
}
}
private string _RainCharacters = "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?";
/**////
/// 获取、设置字符雨中可能出现的字符
///
public string RainCharacters
{
get { return _RainCharacters; }
set
{
if (string.IsNullOrEmpty(value))
value = "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?";
_RainCharacters = value;
CHARACTERS = value.ToCharArray();
}
}
private Color _RainHeadColor = Color.Lime;
/**////
/// 获取、设置字符雨头的颜色
///
public Color RainHeadColor
{
get { return _RainHeadColor; }
set
{
if (!Running)
_RainHeadColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainBodyColor = Color.Green;
/**////
/// 获取、设置字符雨体的颜色
///
public Color RainBodyColor
{
get { return _RainBodyColor; }
set
{
if (!Running)
_RainBodyColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainTailColor = Color.DarkGreen;
/**////
/// 获取、设置字符雨体的颜色
///
public Color RainTailColor
{
get { return _RainTailColor; }
set
{
if (!Running)
_RainTailColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Font _RainFont = new Font(new FontFamily("Consolas"), 12);
/**////
/// 获取、设置字符雨的字体样式
///
public Font RainFont
{
get { return _RainFont; }
set
{
if (!Running)
_RainFont = value;
else
throw new Exception("运行中不可以更改字体。");
}
}
private int _StreamsCount = 100;
/**////
/// 获取、设置字符雨的数量
///
public int StreamsCount
{
get { return _StreamsCount; }
set
{
if (!Running)
_StreamsCount = value;
else
throw new Exception("运行中不可以更改数量。");
}
}
private int _MaxLength = 50;
/**////
/// 获取、设置每个雨滴的最大字符数
///
public int MaxLength
{
get { return _MaxLength; }
set
{
if (!Running)
{
if (value >= _MinLength)
_MaxLength = value;
else
throw new Exception("最大字符数不能小于最小字符数。");
}
else
throw new Exception("运行中不可以更改数量。");
}
}
private int _MinLength = 20;
/**////
/// 获取、设置每个雨滴的最小字符数
///
public int MinLength
{
get { return _MinLength; }
set
{
if (!Running)
{
if (value <= _MaxLength)
_MinLength = value;
else
throw new Exception("最小字符数不能大于最大字符数。");
}
else
throw new Exception("运行中不可以更改数量。");
}
}
public bool Running
{
get { return RainThread != null && RainThread.IsAlive; }
}
private Thread RainThread;
private bool RUN;
private bool PAUSE;
private Brush BackBrush = null;
private Brush RainHeadBrush = null;
private Brush RainBodyBrush = null;
private Brush RainTailBrush = null;
/**////
/// 开始显示字符雨
///
public void Start()
{
if (_ShowWindow == null)
throw new Exception("没有用于显示的窗口(或控件)");
if (!Running)
{
RainThread = new Thread(new ParameterizedThreadStart(RainProcess));
RUN = true;
PAUSE = false;
Ready();
RainThread.Start();
}
}
private void Ready()
{
Rain.RainFont = _RainFont;
Rain.RainHeadColor = _RainHeadColor;
Rain.RainBodyColor = _RainBodyColor;
Rain.RainTailColor = _RainTailColor;
Rain.BackColor = _ShowWindow.BackColor;
if (RainHeadBrush != null)
RainHeadBrush.Dispose();
if (RainBodyBrush != null)
RainBodyBrush.Dispose();
if (RainTailBrush != null)
RainTailBrush.Dispose();
if (BackBrush != null)
BackBrush.Dispose();
RainHeadBrush = new SolidBrush(Rain.RainHeadColor);
RainBodyBrush = new SolidBrush(Rain.RainBodyColor);
RainTailBrush = new SolidBrush(Rain.RainTailColor);
BackBrush = new SolidBrush(Rain.BackColor);
//RainItems.Clear();
using (Graphics g = _ShowWindow.CreateGraphics())
{
g.Clear(Rain.BackColor);
}
}
private EventHandler DrawRainEvent;
void CharacterRainPanel_DrawRainEvent(object sender, EventArgs e)
{
//foreach (Rain.Item item in e.Items)
//{
// _ShowWindow.Invalidate(new Rectangle(item.X, item.Y, item.Width, item.Height));
// _ShowWindow.Update();
//}
using (Graphics g = _ShowWindow.CreateGraphics())
{
g.DrawImage(BMP, 0, 0);
}
//_ShowWindow.Invalidate(true);
//_ShowWindow.Refresh();
}
//private List RainItems = new List();
private object RainLOCK = new object();
private void RainProcess(object Param)
{
using (BMP = new Bitmap(_ShowWindow.Width, _ShowWindow.Height))
{
using (Graph = Graphics.FromImage(BMP))
{
List<Rain> Rains = new List<Rain>();
for (int i = 0; i < _StreamsCount; i++)
Rains.Add(new Rain(_MinLength + Rand.Next(_MaxLength - _MinLength)));
while (RUN)
{
if (PAUSE)
{
Thread.Sleep(300);
continue;
}
DoRain(Rains);
Thread.Sleep(50);
}
foreach (Rain r in Rains)
{
r.Uninit();
}
}
}
}
private void DoRain(List<Rain> Rains)
{
for (int i = 0; i < Rains.Count; i++)
{
Rain rain = Rains[i];
if (!rain.Inited)
{
if (!rain.Init(_ShowWindow.Width, Rand.Next(_ShowWindow.Height / 3)))
continue;
}
Rain.Item item = rain.GetItem(CHARACTERS[Rand.Next(CHARACTERS.Length)]);
Rain.Item prior = null;
if (item == null)
continue;
else
{
lock (BMPLock)
{
if (item.Y <= BMP.Height)
{
if (item.Type == Rain.Item.RainItemType.Head && rain.Prior.Type != Rain.Item.RainItemType.Tail)
{
rain.Prior.Type = Rain.Item.RainItemType.Body;
prior = rain.Prior;
}
if (item.Type == Rain.Item.RainItemType.Back)
{
prior = rain.Prior;
}
switch (item.Type)
{
case Rain.Item.RainItemType.Head:
{
Graph.DrawString(new string(item.CH, 1), _RainFont, RainHeadBrush, item.X, item.Y);
break;
}
case Rain.Item.RainItemType.Body:
{
Graph.DrawString(new string(item.CH, 1), _RainFont, RainBodyBrush, item.X, item.Y);
break;
}
case Rain.Item.RainItemType.Tail:
{
Graph.DrawString(new string(item.CH, 1), _RainFont, RainTailBrush, item.X, item.Y);
break;
}
case Rain.Item.RainItemType.Back:
{
Graph.FillRectangle(BackBrush, item.X, item.Y, item.Width, item.Height);
break;
}
}
if (prior != null)
{
switch (prior.Type)
{
case Rain.Item.RainItemType.Head:
{
Graph.DrawString(new string(prior.CH, 1), _RainFont, RainHeadBrush, prior.X, prior.Y);
break;
}
case Rain.Item.RainItemType.Body:
{
Graph.DrawString(new string(prior.CH, 1), _RainFont, RainBodyBrush, prior.X, prior.Y);
break;
}
case Rain.Item.RainItemType.Tail:
{
Graph.DrawString(new string(prior.CH, 1), _RainFont, RainTailBrush, prior.X, prior.Y);
break;
}
case Rain.Item.RainItemType.Back:
{
Graph.FillRectangle(BackBrush, prior.X, prior.Y, prior.Width, prior.Height);
break;
}
}
}
}
else
{
item.Owner.Way = Rain.RainWay.Reverse;
}
}
}
}
try
{
if (!_ShowWindow.Disposing)
_ShowWindow.Invoke(DrawRainEvent, this, new EventArgs());
}
catch
{
}
}
/**////
/// 停止显示字符雨
///
public void Stop()
{
RUN = false;
}
/**////
/// 暂停显示
///
public void Pause()
{
PAUSE = true;
}
/**////
/// 恢复暂停
///
public void Resume()
{
PAUSE = false;
}
//protected void Paint()
//{
// lock (RainLOCK)
// {
// for (int i = RainItems.Count - 1; i >= 0; i--)
// {
// Rain.Item item = RainItems[i];
// if (item.X < BMP.Width)
// {
// if (item.Y < BMP.Height)
// {
// //if (e.ClipRectangle.X <= item.X && e.ClipRectangle.Y <= item.Y && e.ClipRectangle.Width >= item.Width && e.ClipRectangle.Height >= item.Height)
// {
// switch (item.Type)
// {
// case Rain.Item.RainItemType.Head:
// {
// e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainHeadBrush, item.X, item.Y);
// break;
// }
// case Rain.Item.RainItemType.Body:
// {
// e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainBodyBrush, item.X, item.Y);
// break;
// }
// case Rain.Item.RainItemType.Tail:
// {
// e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainTailBrush, item.X, item.Y);
// break;
// }
// case Rain.Item.RainItemType.Back:
// {
// e.Graphics.FillRectangle(BackBrush, item.X, item.Y, item.Width, item.Height);
// break;
// }
// }
// }
// }
// else
// {
// item.Owner.Way = Rain.RainWay.Reverse;
// }
// }
// if (item.Type == Rain.Item.RainItemType.Back)
// {
// RainItems.Remove(item);
// }
// }
// }
//}
private class Rain
{
private static Font _RainFont;
public static Font RainFont
{
get { return _RainFont; }
set
{
_RainFont = value;
_RainHeight = (int)(value.Size * value.FontFamily.GetLineSpacing(FontStyle.Regular) / value.FontFamily.GetEmHeight(FontStyle.Regular)) + 1;
}
}
public static Color BackColor;
public static Color RainBodyColor;
public static Color RainHeadColor;
public static Color RainTailColor;
private static int _RainHeight;
public static int RainHeight
{
get { return _RainHeight; }
}
private static object RangeLock = new object();
private static List<Rectangle> Ranges = new List<Rectangle>();
Queue<Item> Chars = new Queue<Item>();
private int _Length;
private int _BeginX;
private int _BeginY;
private RainWay _Way;
public RainWay Way
{
get { return _Way; }
set { _Way = value; }
}
private Rectangle Range;
public enum RainWay : byte
{
/**////
/// 正向
///
Obverse = 0,
/**////
/// 反向
///
Reverse = 1
}
public bool Inited
{
get { return Chars.Count > 0; }
}
public bool Init(int Width, int Y)
{
bool Ret = true;
Uninit();
if (Rand.Next(30) < 10)
return false;
_BeginX = Rand.Next(Width);
Size s = TextRenderer.MeasureText(" ", _RainFont);
Range = new Rectangle(_BeginX, Y, s.Width, s.Height * _Length);
foreach (Rectangle r in Ranges)
{
if (r.Contains(this.Range) || r.IntersectsWith(this.Range))
{
Ret = false;
break;
}
}
if (Ret)
Ranges.Add(this.Range);
_BeginY = Y;
_Way = RainWay.Obverse;
_Prior = null;
return Ret;
}
public void Uninit()
{
if (this.Range != null && Ranges.Contains(this.Range))
Ranges.Remove(this.Range);
}
item#region item
public class Item
{
private Rain _Owner;
public Rain Owner
{
get { return _Owner; }
}
public enum RainItemType : byte
{
Head = 0,
Body = 1,
Tail = 2,
Back = 3
}
private char _CH;
public char CH
{
get { return _CH; }
}
private int _X;
public int X
{
get { return _X; }
}
private int _Y;
public int Y
{
get { return _Y; }
}
private int _Width;
public int Width
{
get { return _Width; }
}
private int _Height;
public int Height
{
get { return _Height; }
}
private RainItemType _Type;
public RainItemType Type
{
get { return _Type; }
set { _Type = value; }
}
public Item(Rain Owner, char CH, int X, int Y, RainItemType Type)
{
this._Owner = Owner;
this._CH = CH;
this._X = X;
this._Y = Y;
Size s = TextRenderer.MeasureText(new string(CH, 1), RainFont);
this._Width = s.Width;
this._Height = s.Height;
this._Type = Type;
}
}
#endregion
public Rain(int Length)
{
_Length = Length;
}
public Item GetItem(char CH)
{
Item Ret = null;
if (_Way == RainWay.Obverse)
{
Ret = Add(CH);
if (Ret == null)
_Way = RainWay.Reverse;
}
else
{
Ret = Remove();
if (Ret == null)
_Way = RainWay.Obverse;
}
return Ret;
}
private Item _Prior = null;
public Item Prior
{
get
{
return _Prior;
}
}
private Item Add(char CH)
{
Item Ret = null;
if (Chars.Count < _Length)
{
Ret = new Item(this, CH, _BeginX, _BeginY + RainHeight * Chars.Count, Chars.Count == 0 ? Item.RainItemType.Tail : Item.RainItemType.Head);
if (Ret.Type == Item.RainItemType.Head)
_Prior = Chars.Last();
Chars.Enqueue(Ret);
}
return Ret;
}
private Item Remove()
{
Item Ret = null;
if (Chars.Count > 0)
{
Ret = Chars.Dequeue();
Ret.Type = Item.RainItemType.Back;
if (Chars.Count > 0)
{
_Prior = Chars.First();
_Prior.Type = Item.RainItemType.Tail;
}
else
_Prior = null;
}
return Ret;
}
}
}
{
/**////
/// 必需的设计器变量。
///
private System.ComponentModel.IContainer components = null;
/**////
/// 清理所有正在使用的资源。
///
/// 如果应释放托管资源,为 true;否则为 false。
protected override void Dispose(bool disposing)
{
if (RainThread != null && RainThread.IsAlive)
Stop();
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
组件设计器生成的代码#region 组件设计器生成的代码
/**////
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
///
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
public CharacterRain()
{
Initialize();
InitializeComponent();
}
public CharacterRain(IContainer container)
{
Initialize();
container.Add(this);
InitializeComponent();
}
private object BMPLock = new object();
private Bitmap BMP;
private Graphics Graph;
private void Initialize()
{
this.DrawRainEvent = new EventHandler(CharacterRainPanel_DrawRainEvent);
OnPaint = new PaintEventHandler(ShowWindow_Paint);
}
private PaintEventHandler OnPaint;
private char[] CHARACTERS = { '`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\\', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '|', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?' };
private static readonly Random Rand = new Random();
private Control _ShowWindow = null;
/**////
/// 获取、设置用于显示字符雨的窗口(或控件)
///
public Control ShowWindow
{
get { return _ShowWindow; }
set
{
if (_ShowWindow != null)
_ShowWindow.Paint -= OnPaint;
_ShowWindow = value;
if (_ShowWindow != null)
_ShowWindow.Paint += OnPaint;
}
}
void ShowWindow_Paint(object sender, PaintEventArgs e)
{
//Paint();
if (BMP != null)
{
lock (BMPLock)
{
//e.Graphics.Clear(_ShowWindow.BackColor);
try
{
e.Graphics.DrawImage(BMP, 0, 0);
}
catch
{
}
}
}
}
private string _RainCharacters = "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?";
/**////
/// 获取、设置字符雨中可能出现的字符
///
public string RainCharacters
{
get { return _RainCharacters; }
set
{
if (string.IsNullOrEmpty(value))
value = "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?";
_RainCharacters = value;
CHARACTERS = value.ToCharArray();
}
}
private Color _RainHeadColor = Color.Lime;
/**////
/// 获取、设置字符雨头的颜色
///
public Color RainHeadColor
{
get { return _RainHeadColor; }
set
{
if (!Running)
_RainHeadColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainBodyColor = Color.Green;
/**////
/// 获取、设置字符雨体的颜色
///
public Color RainBodyColor
{
get { return _RainBodyColor; }
set
{
if (!Running)
_RainBodyColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainTailColor = Color.DarkGreen;
/**////
/// 获取、设置字符雨体的颜色
///
public Color RainTailColor
{
get { return _RainTailColor; }
set
{
if (!Running)
_RainTailColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Font _RainFont = new Font(new FontFamily("Consolas"), 12);
/**////
/// 获取、设置字符雨的字体样式
///
public Font RainFont
{
get { return _RainFont; }
set
{
if (!Running)
_RainFont = value;
else
throw new Exception("运行中不可以更改字体。");
}
}
private int _StreamsCount = 100;
/**////
/// 获取、设置字符雨的数量
///
public int StreamsCount
{
get { return _StreamsCount; }
set
{
if (!Running)
_StreamsCount = value;
else
throw new Exception("运行中不可以更改数量。");
}
}
private int _MaxLength = 50;
/**////
/// 获取、设置每个雨滴的最大字符数
///
public int MaxLength
{
get { return _MaxLength; }
set
{
if (!Running)
{
if (value >= _MinLength)
_MaxLength = value;
else
throw new Exception("最大字符数不能小于最小字符数。");
}
else
throw new Exception("运行中不可以更改数量。");
}
}
private int _MinLength = 20;
/**////
/// 获取、设置每个雨滴的最小字符数
///
public int MinLength
{
get { return _MinLength; }
set
{
if (!Running)
{
if (value <= _MaxLength)
_MinLength = value;
else
throw new Exception("最小字符数不能大于最大字符数。");
}
else
throw new Exception("运行中不可以更改数量。");
}
}
public bool Running
{
get { return RainThread != null && RainThread.IsAlive; }
}
private Thread RainThread;
private bool RUN;
private bool PAUSE;
private Brush BackBrush = null;
private Brush RainHeadBrush = null;
private Brush RainBodyBrush = null;
private Brush RainTailBrush = null;
/**////
/// 开始显示字符雨
///
public void Start()
{
if (_ShowWindow == null)
throw new Exception("没有用于显示的窗口(或控件)");
if (!Running)
{
RainThread = new Thread(new ParameterizedThreadStart(RainProcess));
RUN = true;
PAUSE = false;
Ready();
RainThread.Start();
}
}
private void Ready()
{
Rain.RainFont = _RainFont;
Rain.RainHeadColor = _RainHeadColor;
Rain.RainBodyColor = _RainBodyColor;
Rain.RainTailColor = _RainTailColor;
Rain.BackColor = _ShowWindow.BackColor;
if (RainHeadBrush != null)
RainHeadBrush.Dispose();
if (RainBodyBrush != null)
RainBodyBrush.Dispose();
if (RainTailBrush != null)
RainTailBrush.Dispose();
if (BackBrush != null)
BackBrush.Dispose();
RainHeadBrush = new SolidBrush(Rain.RainHeadColor);
RainBodyBrush = new SolidBrush(Rain.RainBodyColor);
RainTailBrush = new SolidBrush(Rain.RainTailColor);
BackBrush = new SolidBrush(Rain.BackColor);
//RainItems.Clear();
using (Graphics g = _ShowWindow.CreateGraphics())
{
g.Clear(Rain.BackColor);
}
}
private EventHandler DrawRainEvent;
void CharacterRainPanel_DrawRainEvent(object sender, EventArgs e)
{
//foreach (Rain.Item item in e.Items)
//{
// _ShowWindow.Invalidate(new Rectangle(item.X, item.Y, item.Width, item.Height));
// _ShowWindow.Update();
//}
using (Graphics g = _ShowWindow.CreateGraphics())
{
g.DrawImage(BMP, 0, 0);
}
//_ShowWindow.Invalidate(true);
//_ShowWindow.Refresh();
}
//private List
private object RainLOCK = new object();
private void RainProcess(object Param)
{
using (BMP = new Bitmap(_ShowWindow.Width, _ShowWindow.Height))
{
using (Graph = Graphics.FromImage(BMP))
{
List<Rain> Rains = new List<Rain>();
for (int i = 0; i < _StreamsCount; i++)
Rains.Add(new Rain(_MinLength + Rand.Next(_MaxLength - _MinLength)));
while (RUN)
{
if (PAUSE)
{
Thread.Sleep(300);
continue;
}
DoRain(Rains);
Thread.Sleep(50);
}
foreach (Rain r in Rains)
{
r.Uninit();
}
}
}
}
private void DoRain(List<Rain> Rains)
{
for (int i = 0; i < Rains.Count; i++)
{
Rain rain = Rains[i];
if (!rain.Inited)
{
if (!rain.Init(_ShowWindow.Width, Rand.Next(_ShowWindow.Height / 3)))
continue;
}
Rain.Item item = rain.GetItem(CHARACTERS[Rand.Next(CHARACTERS.Length)]);
Rain.Item prior = null;
if (item == null)
continue;
else
{
lock (BMPLock)
{
if (item.Y <= BMP.Height)
{
if (item.Type == Rain.Item.RainItemType.Head && rain.Prior.Type != Rain.Item.RainItemType.Tail)
{
rain.Prior.Type = Rain.Item.RainItemType.Body;
prior = rain.Prior;
}
if (item.Type == Rain.Item.RainItemType.Back)
{
prior = rain.Prior;
}
switch (item.Type)
{
case Rain.Item.RainItemType.Head:
{
Graph.DrawString(new string(item.CH, 1), _RainFont, RainHeadBrush, item.X, item.Y);
break;
}
case Rain.Item.RainItemType.Body:
{
Graph.DrawString(new string(item.CH, 1), _RainFont, RainBodyBrush, item.X, item.Y);
break;
}
case Rain.Item.RainItemType.Tail:
{
Graph.DrawString(new string(item.CH, 1), _RainFont, RainTailBrush, item.X, item.Y);
break;
}
case Rain.Item.RainItemType.Back:
{
Graph.FillRectangle(BackBrush, item.X, item.Y, item.Width, item.Height);
break;
}
}
if (prior != null)
{
switch (prior.Type)
{
case Rain.Item.RainItemType.Head:
{
Graph.DrawString(new string(prior.CH, 1), _RainFont, RainHeadBrush, prior.X, prior.Y);
break;
}
case Rain.Item.RainItemType.Body:
{
Graph.DrawString(new string(prior.CH, 1), _RainFont, RainBodyBrush, prior.X, prior.Y);
break;
}
case Rain.Item.RainItemType.Tail:
{
Graph.DrawString(new string(prior.CH, 1), _RainFont, RainTailBrush, prior.X, prior.Y);
break;
}
case Rain.Item.RainItemType.Back:
{
Graph.FillRectangle(BackBrush, prior.X, prior.Y, prior.Width, prior.Height);
break;
}
}
}
}
else
{
item.Owner.Way = Rain.RainWay.Reverse;
}
}
}
}
try
{
if (!_ShowWindow.Disposing)
_ShowWindow.Invoke(DrawRainEvent, this, new EventArgs());
}
catch
{
}
}
/**////
/// 停止显示字符雨
///
public void Stop()
{
RUN = false;
}
/**////
/// 暂停显示
///
public void Pause()
{
PAUSE = true;
}
/**////
/// 恢复暂停
///
public void Resume()
{
PAUSE = false;
}
//protected void Paint()
//{
// lock (RainLOCK)
// {
// for (int i = RainItems.Count - 1; i >= 0; i--)
// {
// Rain.Item item = RainItems[i];
// if (item.X < BMP.Width)
// {
// if (item.Y < BMP.Height)
// {
// //if (e.ClipRectangle.X <= item.X && e.ClipRectangle.Y <= item.Y && e.ClipRectangle.Width >= item.Width && e.ClipRectangle.Height >= item.Height)
// {
// switch (item.Type)
// {
// case Rain.Item.RainItemType.Head:
// {
// e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainHeadBrush, item.X, item.Y);
// break;
// }
// case Rain.Item.RainItemType.Body:
// {
// e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainBodyBrush, item.X, item.Y);
// break;
// }
// case Rain.Item.RainItemType.Tail:
// {
// e.Graphics.DrawString(new string(item.CH, 1), _RainFont, RainTailBrush, item.X, item.Y);
// break;
// }
// case Rain.Item.RainItemType.Back:
// {
// e.Graphics.FillRectangle(BackBrush, item.X, item.Y, item.Width, item.Height);
// break;
// }
// }
// }
// }
// else
// {
// item.Owner.Way = Rain.RainWay.Reverse;
// }
// }
// if (item.Type == Rain.Item.RainItemType.Back)
// {
// RainItems.Remove(item);
// }
// }
// }
//}
private class Rain
{
private static Font _RainFont;
public static Font RainFont
{
get { return _RainFont; }
set
{
_RainFont = value;
_RainHeight = (int)(value.Size * value.FontFamily.GetLineSpacing(FontStyle.Regular) / value.FontFamily.GetEmHeight(FontStyle.Regular)) + 1;
}
}
public static Color BackColor;
public static Color RainBodyColor;
public static Color RainHeadColor;
public static Color RainTailColor;
private static int _RainHeight;
public static int RainHeight
{
get { return _RainHeight; }
}
private static object RangeLock = new object();
private static List<Rectangle> Ranges = new List<Rectangle>();
Queue<Item> Chars = new Queue<Item>();
private int _Length;
private int _BeginX;
private int _BeginY;
private RainWay _Way;
public RainWay Way
{
get { return _Way; }
set { _Way = value; }
}
private Rectangle Range;
public enum RainWay : byte
{
/**////
/// 正向
///
Obverse = 0,
/**////
/// 反向
///
Reverse = 1
}
public bool Inited
{
get { return Chars.Count > 0; }
}
public bool Init(int Width, int Y)
{
bool Ret = true;
Uninit();
if (Rand.Next(30) < 10)
return false;
_BeginX = Rand.Next(Width);
Size s = TextRenderer.MeasureText(" ", _RainFont);
Range = new Rectangle(_BeginX, Y, s.Width, s.Height * _Length);
foreach (Rectangle r in Ranges)
{
if (r.Contains(this.Range) || r.IntersectsWith(this.Range))
{
Ret = false;
break;
}
}
if (Ret)
Ranges.Add(this.Range);
_BeginY = Y;
_Way = RainWay.Obverse;
_Prior = null;
return Ret;
}
public void Uninit()
{
if (this.Range != null && Ranges.Contains(this.Range))
Ranges.Remove(this.Range);
}
item#region item
public class Item
{
private Rain _Owner;
public Rain Owner
{
get { return _Owner; }
}
public enum RainItemType : byte
{
Head = 0,
Body = 1,
Tail = 2,
Back = 3
}
private char _CH;
public char CH
{
get { return _CH; }
}
private int _X;
public int X
{
get { return _X; }
}
private int _Y;
public int Y
{
get { return _Y; }
}
private int _Width;
public int Width
{
get { return _Width; }
}
private int _Height;
public int Height
{
get { return _Height; }
}
private RainItemType _Type;
public RainItemType Type
{
get { return _Type; }
set { _Type = value; }
}
public Item(Rain Owner, char CH, int X, int Y, RainItemType Type)
{
this._Owner = Owner;
this._CH = CH;
this._X = X;
this._Y = Y;
Size s = TextRenderer.MeasureText(new string(CH, 1), RainFont);
this._Width = s.Width;
this._Height = s.Height;
this._Type = Type;
}
}
#endregion
public Rain(int Length)
{
_Length = Length;
}
public Item GetItem(char CH)
{
Item Ret = null;
if (_Way == RainWay.Obverse)
{
Ret = Add(CH);
if (Ret == null)
_Way = RainWay.Reverse;
}
else
{
Ret = Remove();
if (Ret == null)
_Way = RainWay.Obverse;
}
return Ret;
}
private Item _Prior = null;
public Item Prior
{
get
{
return _Prior;
}
}
private Item Add(char CH)
{
Item Ret = null;
if (Chars.Count < _Length)
{
Ret = new Item(this, CH, _BeginX, _BeginY + RainHeight * Chars.Count, Chars.Count == 0 ? Item.RainItemType.Tail : Item.RainItemType.Head);
if (Ret.Type == Item.RainItemType.Head)
_Prior = Chars.Last();
Chars.Enqueue(Ret);
}
return Ret;
}
private Item Remove()
{
Item Ret = null;
if (Chars.Count > 0)
{
Ret = Chars.Dequeue();
Ret.Type = Item.RainItemType.Back;
if (Chars.Count > 0)
{
_Prior = Chars.First();
_Prior.Type = Item.RainItemType.Tail;
}
else
_Prior = null;
}
return Ret;
}
}
}
测试程序下载
使用的时候,先设定ShowWindow,这个属性决定在哪个控件上显示字符雨,然后还可以设置如下属性:
MaxLength:每条字符雨的最大字符数量
MinLength:每条字符雨的最小字符数量
RainBodyColor:字符雨中间的颜色
RainCharacters:字符雨可以使用到的字符
FainFont:字体
RainHeadColor:最前面的字符的颜色
RainTailColor:最后面字符的颜色
StreamsCount:字符雨的数量
还有如下方法可供调用:
Start:开始显示
Stop:停止显示
Pause:暂停显示
Resume:恢复暂停