在做一个WinForm登录框时,突然想到,如果有黑客帝国中字符雨的特效做背景,那应该蛮Cool的,所以就有了如下代码,随意写的,有点乱。
public partial class CharacterRain : Component
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (RainThread != null && RainThread.IsAlive)
Stop();
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
组件设计器生成的代码
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;
/// <summary>
/// 获取、设置用于显示字符雨的窗口(或控件)
/// </summary>
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<>?";
/// <summary>
/// 获取、设置字符雨中可能出现的字符
/// </summary>
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;
/// <summary>
/// 获取、设置字符雨头的颜色
/// </summary>
public Color RainHeadColor
{
get { return _RainHeadColor; }
set
{
if (!Running)
_RainHeadColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainBodyColor = Color.Green;
/// <summary>
/// 获取、设置字符雨体的颜色
/// </summary>
public Color RainBodyColor
{
get { return _RainBodyColor; }
set
{
if (!Running)
_RainBodyColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainTailColor = Color.DarkGreen;
/// <summary>
/// 获取、设置字符雨体的颜色
/// </summary>
public Color RainTailColor
{
get { return _RainTailColor; }
set
{
if (!Running)
_RainTailColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Font _RainFont = new Font(new FontFamily("Consolas"), 12);
/// <summary>
/// 获取、设置字符雨的字体样式
/// </summary>
public Font RainFont
{
get { return _RainFont; }
set
{
if (!Running)
_RainFont = value;
else
throw new Exception("运行中不可以更改字体。");
}
}
private int _StreamsCount = 100;
/// <summary>
/// 获取、设置字符雨的数量
/// </summary>
public int StreamsCount
{
get { return _StreamsCount; }
set
{
if (!Running)
_StreamsCount = value;
else
throw new Exception("运行中不可以更改数量。");
}
}
private int _MaxLength = 50;
/// <summary>
/// 获取、设置每个雨滴的最大字符数
/// </summary>
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;
/// <summary>
/// 获取、设置每个雨滴的最小字符数
/// </summary>
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;
/// <summary>
/// 开始显示字符雨
/// </summary>
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<Rain.Item> RainItems = new List<Rain.Item>();
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
{
}
}
/// <summary>
/// 停止显示字符雨
/// </summary>
public void Stop()
{
RUN = false;
}
/// <summary>
/// 暂停显示
/// </summary>
public void Pause()
{
PAUSE = true;
}
/// <summary>
/// 恢复暂停
/// </summary>
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
{
/// <summary>
/// 正向
/// </summary>
Obverse = 0,
/// <summary>
/// 反向
/// </summary>
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
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;
}
}
}
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (RainThread != null && RainThread.IsAlive)
Stop();
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
组件设计器生成的代码
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;
/// <summary>
/// 获取、设置用于显示字符雨的窗口(或控件)
/// </summary>
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<>?";
/// <summary>
/// 获取、设置字符雨中可能出现的字符
/// </summary>
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;
/// <summary>
/// 获取、设置字符雨头的颜色
/// </summary>
public Color RainHeadColor
{
get { return _RainHeadColor; }
set
{
if (!Running)
_RainHeadColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainBodyColor = Color.Green;
/// <summary>
/// 获取、设置字符雨体的颜色
/// </summary>
public Color RainBodyColor
{
get { return _RainBodyColor; }
set
{
if (!Running)
_RainBodyColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Color _RainTailColor = Color.DarkGreen;
/// <summary>
/// 获取、设置字符雨体的颜色
/// </summary>
public Color RainTailColor
{
get { return _RainTailColor; }
set
{
if (!Running)
_RainTailColor = value;
else
throw new Exception("运行中不可以更改颜色。");
}
}
private Font _RainFont = new Font(new FontFamily("Consolas"), 12);
/// <summary>
/// 获取、设置字符雨的字体样式
/// </summary>
public Font RainFont
{
get { return _RainFont; }
set
{
if (!Running)
_RainFont = value;
else
throw new Exception("运行中不可以更改字体。");
}
}
private int _StreamsCount = 100;
/// <summary>
/// 获取、设置字符雨的数量
/// </summary>
public int StreamsCount
{
get { return _StreamsCount; }
set
{
if (!Running)
_StreamsCount = value;
else
throw new Exception("运行中不可以更改数量。");
}
}
private int _MaxLength = 50;
/// <summary>
/// 获取、设置每个雨滴的最大字符数
/// </summary>
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;
/// <summary>
/// 获取、设置每个雨滴的最小字符数
/// </summary>
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;
/// <summary>
/// 开始显示字符雨
/// </summary>
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<Rain.Item> RainItems = new List<Rain.Item>();
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
{
}
}
/// <summary>
/// 停止显示字符雨
/// </summary>
public void Stop()
{
RUN = false;
}
/// <summary>
/// 暂停显示
/// </summary>
public void Pause()
{
PAUSE = true;
}
/// <summary>
/// 恢复暂停
/// </summary>
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
{
/// <summary>
/// 正向
/// </summary>
Obverse = 0,
/// <summary>
/// 反向
/// </summary>
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
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:恢复暂停