这是一个比较复杂的程序,包含了30种图像动画特效演示,使用C#编写,源程序大概2000多行。
这个软件实际上主要是四个方面的内容:
1、30种动画特效算法,包含诸如随机拉丝、交替分块、多经扫描等等。这些算法设计的比较巧妙,也就是说大量的使用了图像处理的一些技巧。
2、.NET的GDI+技术功能非常强大,本软件中几乎涉及了GDI+中的各个方面,例如仿射变换矩阵、颜色变换矩阵、块处理等等。
3、采用多线程技术,使得软件看起来比较有序,同时采用信号量来实现暂停、继续、取消等功能。
4、采用比较严谨的面向对象的程序设计技术,从类的定义到方法的、事件的定义都严格按照OOP理论完成,可以说比较完整、精确的体现了OOP精髓。
这是截屏动画效果:
由于源程序太多,所以分三次发出,这次是(上),先发前10个动画特效:
- using System;
- using System.Drawing;
- using System.Drawing.Drawing2D;
- using System.Drawing.Imaging;
- using System.Threading;
- using System.Windows.Forms;
- namespace Mengliao.CSharp.A14
- {
- #region 动画类型枚举
- // 本例为了简单起见没有使用见名知意的名称,如用于实际可将这些枚举成员更名为准确的英文名称
- enum AnimateType
- {
- Animator01, Animator02, Animator03, Animator04, Animator05,
- Animator06, Animator07, Animator08, Animator09, Animator10,
- Animator11, Animator12, Animator13, Animator14, Animator15,
- Animator16, Animator17, Animator18, Animator19, Animator20,
- Animator21, Animator22, Animator23, Animator24, Animator25,
- Animator26, Animator27, Animator28, Animator29, Animator30
- }
- #endregion
- class AnimatorImage
- {
- #region 私有字段
- // 输入位图
- private Bitmap bmp;
- // 是否已经开始绘制
- private bool drawStarted = false;
- // 在绘制过程中是否终止的自动复位信号量,有信号则终止
- private AutoResetEvent cancelEvent = new AutoResetEvent(false);
- // 在绘制过程中是否暂停的手动复位信号量,有信号则暂停
- private ManualResetEvent pauseEvent = new ManualResetEvent(false);
- // 输出位图的DC
- private Graphics dc;
- #endregion
- #region 属性和事件
- private Bitmap outBmp;
- /// <summary>
- /// 输出位图。
- /// </summary>
- public Bitmap OutBmp
- {
- get { return outBmp; }
- }
- private int delay;
- /// <summary>
- /// 延时系数。
- /// </summary>
- public int Delay
- {
- get { return delay; }
- set { delay = Math.Min(Math.Max(1, value), 100); } // 使其介于1到100之间
- }
- /// <summary>
- /// 重绘事件。
- /// </summary>
- public event PaintEventHandler Redraw;
- protected void OnRedraw(Rectangle clipRectangle)
- {
- if (Redraw != null)
- {
- Redraw.Invoke(this, new PaintEventArgs(dc, clipRectangle));
- }
- }
- /// <summary>
- /// 绘制开始事件。
- /// </summary>
- public event EventHandler DrawStarted;
- protected void OnDrawStarted(object sender, EventArgs e)
- {
- drawStarted = true;
- if (DrawStarted != null)
- {
- DrawStarted.Invoke(sender, e);
- }
- }
- /// <summary>
- /// 绘制完成事件。
- /// </summary>
- public event EventHandler DrawCompleted;
- protected void OnDrawCompleted(object sender, EventArgs e)
- {
- drawStarted = false;
- cancelEvent.Reset();
- if (DrawCompleted != null)
- {
- DrawCompleted.Invoke(sender, e);
- }
- }
- #endregion
- #region 私有方法
- // 在输出位图上显示绘制过程中的错误信息
- private void ShowError(string errMsg)
- {
- Font font = new Font("宋体", 9);
- SizeF size = dc.MeasureString(errMsg, font);
- PointF point = new PointF((outBmp.Width - size.Width) / 2f, (outBmp.Height - size.Height) / 2f);
- // 在文字的四个方向各一个像素处绘制其它颜色的文字,以形成边框,否则可能看不清除文字
- dc.DrawString(errMsg, font, Brushes.Red, point.X - 1f, point.Y);
- dc.DrawString(errMsg, font, Brushes.Red, point.X + 1f, point.Y);
- dc.DrawString(errMsg, font, Brushes.Red, point.X, point.Y - 1f);
- dc.DrawString(errMsg, font, Brushes.Red, point.X, point.Y + 1f);
- // 绘制文字
- dc.DrawString(errMsg, font, Brushes.White, point);
- ShowBmp(new Rectangle(Point.Round(point), Size.Round(size)));
- }
- // 供绘制动画方法内部调用,三个重载版本
- private void ShowBmp(Rectangle clipRectangle)
- {
- string cancelMsg = "绘图操作已被用户取消!";
- OnRedraw(clipRectangle);
- if (cancelEvent.WaitOne(0)) // 取消
- {
- // 该异常将被外部方法捕获,即各个绘制方法
- throw new ApplicationException(cancelMsg);
- }
- while (pauseEvent.WaitOne(0)) // 暂停
- {
- if (cancelEvent.WaitOne(10)) // 在暂停期间取消
- {
- pauseEvent.Reset();
- throw new ApplicationException(cancelMsg);
- }
- }
- }
- private void ShowBmp(RectangleF clipRectangle) // 接收浮点参数
- {
- ShowBmp(Rectangle.Round(clipRectangle));
- }
- private void ShowBmp() // 重绘全部区域
- {
- ShowBmp(new Rectangle(0, 0, bmp.Width, bmp.Height));
- }
- // 清空背景
- private void ClearBackground()
- {
- dc.Clear(Color.FromKnownColor(KnownColor.ButtonFace)); // 置背景色
- ShowBmp(); // 重绘所有区域
- }
- #endregion
- #region 动画控制
- /// <summary>
- /// 取消绘制。
- /// </summary>
- public void CancelDraw()
- {
- if (drawStarted)
- {
- cancelEvent.Set();
- }
- }
- /// <summary>
- /// 暂停绘制。
- /// </summary>
- public void PauseDraw()
- {
- if (drawStarted)
- {
- pauseEvent.Set();
- }
- }
- /// <summary>
- /// 继续绘制。
- /// </summary>
- public void ResumeDraw()
- {
- if (drawStarted)
- {
- pauseEvent.Reset();
- }
- }
- #endregion
- #region 构造函数
- /// <summary>
- /// 实例化后,需分配事件处理方法,所有事件均在独立线程中触发;默认延时系数为1。
- /// </summary>
- /// <param name="inBmp">输入位图</param>
- public AnimatorImage(Bitmap inBmp)
- {
- delay = 1;
- this.bmp = (Bitmap)inBmp.Clone();
- outBmp = new Bitmap(this.bmp.Width, this.bmp.Height);
- dc = Graphics.FromImage(outBmp);
- }
- #endregion
- #region 绘制动画
- /// <summary>
- /// 以独立线程的方式开始显示动画。
- /// </summary>
- /// <param name="animateType">动画类型枚举</param>
- public void DrawAnimator(AnimateType animateType)
- {
- if (drawStarted) // 判断动画是否已经开始绘制
- {
- if (pauseEvent.WaitOne(0)) // 动画已开始,但被暂停了,继续
- pauseEvent.Reset();
- else
- pauseEvent.Set();
- return;
- }
- ThreadStart threadMethod;
- switch (animateType)
- {
- case AnimateType.Animator01:
- threadMethod = Animator01;
- break;
- case AnimateType.Animator02:
- threadMethod = Animator02;
- break;
- case AnimateType.Animator03:
- threadMethod = Animator03;
- break;
- case AnimateType.Animator04:
- threadMethod = Animator04;
- break;
- case AnimateType.Animator05:
- threadMethod = Animator05;
- break;
- case AnimateType.Animator06:
- threadMethod = Animator06;
- break;
- case AnimateType.Animator07:
- threadMethod = Animator07;
- break;
- case AnimateType.Animator08:
- threadMethod = Animator08;
- break;
- case AnimateType.Animator09:
- threadMethod = Animator09;
- break;
- case AnimateType.Animator10:
- threadMethod = Animator10;
- break;
- case AnimateType.Animator11:
- threadMethod = Animator11;
- break;
- case AnimateType.Animator12:
- threadMethod = Animator12;
- break;
- case AnimateType.Animator13:
- threadMethod = Animator13;
- break;
- case AnimateType.Animator14:
- threadMethod = Animator14;
- break;
- case AnimateType.Animator15:
- threadMethod = Animator15;
- break;
- case AnimateType.Animator16:
- threadMethod = Animator16;
- break;
- case AnimateType.Animator17:
- threadMethod = Animator17;
- break;
- case AnimateType.Animator18:
- threadMethod = Animator18;
- break;
- case AnimateType.Animator19:
- threadMethod = Animator19;
- break;
- case AnimateType.Animator20:
- threadMethod = Animator20;
- break;
- case AnimateType.Animator21:
- threadMethod = Animator21;
- break;
- case AnimateType.Animator22:
- threadMethod = Animator22;
- break;
- case AnimateType.Animator23:
- threadMethod = Animator23;
- break;
- case AnimateType.Animator24:
- threadMethod = Animator24;
- break;
- case AnimateType.Animator25:
- threadMethod = Animator25;
- break;
- case AnimateType.Animator26:
- threadMethod = Animator26;
- break;
- case AnimateType.Animator27:
- threadMethod = Animator27;
- break;
- case AnimateType.Animator28:
- threadMethod = Animator28;
- break;
- case AnimateType.Animator29:
- threadMethod = Animator29;
- break;
- default:
- threadMethod = Animator30;
- break;
- }
- Thread drawThread = new Thread(threadMethod);
- drawThread.IsBackground = true; // 设为后台线程,避免该线程未结束时退出主线程而引发异常
- drawThread.Start();
- }
- #endregion
- // ==========
- // 动画算法
- // ==========
- #region 压缩反转(改进版)
- // 原理:计算图像位置和高度,以高度的一半为轴进行对换上下半边的图像
- private void Animator01()
- {
- const float blockSize = 8; // 每次显示的高度增量,应能被高度整除
- try
- {
- OnDrawStarted(this, EventArgs.Empty); // 触发开始绘制事件
- //ClearBackground();
- Color bgColor = Color.FromKnownColor(KnownColor.ButtonFace);
- RectangleF srcRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
- for (float i = (float)Math.Floor(-bmp.Height / blockSize); i <= Math.Ceiling(bmp.Height / blockSize); i++)
- {
- dc.Clear(bgColor); // 清空DC
- float j = i * blockSize / 2;
- float destTop = bmp.Height / 2 - j; // 目标矩形的顶位置
- // 目标矩形区域在循环的前半段为垂直反向
- RectangleF destRect = new RectangleF(0, destTop, bmp.Width, 2 * j);
- // 在指定区域绘制图像,该图像被拉伸
- dc.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel);
- ShowBmp();
- Thread.Sleep(10 * delay); // 休眠
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty); // 触发完成绘制事件
- }
- }
- #endregion
- #region 垂直对接(改进版)
- // 原理:将图像分为上下部分,然后同时向中心移动
- private void Animator02()
- {
- const int stepCount = 4; // 每次上下移动的步长像素,应能被高度整除
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- Rectangle sourTopRect = new Rectangle(0, 0, bmp.Width, bmp.Height / 2); // 上半部分源区域
- Rectangle sourBottRect = new Rectangle(0, bmp.Height / 2, bmp.Width, bmp.Height / 2); // 下半部分源区域
- for (int i = 0; i <= bmp.Height / 2; i += stepCount)
- {
- Rectangle destTopRect = new Rectangle(0, i - bmp.Height / 2 + 1, bmp.Width, bmp.Height / 2); // 上半部分目标区域
- Rectangle destBottRect = new Rectangle(0, bmp.Height - i - 1, bmp.Width, bmp.Height / 2); // 下半部分目标区域
- dc.DrawImage(bmp, destTopRect, sourTopRect, GraphicsUnit.Pixel);
- dc.DrawImage(bmp, destBottRect, sourBottRect, GraphicsUnit.Pixel);
- ShowBmp(Rectangle.Union(destTopRect, destBottRect));
- Thread.Sleep(10 * delay);
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 中心闭幕(改进版)
- // 原理:由大到小生成图像中心区域,然后用总区域减去该中心区域,并用材质画刷填充
- private void Animator03()
- {
- const float stepCount = 4; // 每次收缩的步长像素
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- // 建立空区域,如使用Region的无参构造函数则建立一个无限大小的区域,而非空区域
- Region region = new Region(new GraphicsPath());
- // 建立位图材质画刷
- TextureBrush textureBrush = new TextureBrush(bmp);
- for (float x = 0; x <= bmp.Width / 2f; x += stepCount)
- {
- // 添加整个位图区域
- region.Union(new Rectangle(0, 0, bmp.Width, bmp.Height));
- // 从中心开始,由大到小填充背景色或填充缩小尺寸的原图
- // 计算高度变化量,如果宽度大,则高度变化量小于宽度,否则大于宽度
- float y = x * bmp.Height / bmp.Width;
- RectangleF rect = new RectangleF(x, y, bmp.Width - 2f * x, bmp.Height - 2f * y);
- // 计算整个位图区域与背景色区域的差集
- region.Exclude(rect);
- dc.FillRegion(textureBrush, region); // 使用材质画刷填充区域
- ShowBmp(region.GetBounds(dc));
- Thread.Sleep(10 * delay);
- }
- // 由于stepCount可能无法被宽度整除,则最终生成的背景色区域并不为空,故在循环结束后绘制整个位图
- dc.DrawImage(bmp, 0, 0);
- ShowBmp();
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 中心放大(改进版)
- // 原理:由中心向边缘按高度和宽度的比例循环输出所有像素,直到高度和宽度为原始大小
- private void Animator04()
- {
- const int stepCount = 4; // 每次增加的像素量,应能被宽度整除
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- Rectangle sourRect = new Rectangle(0, 0, bmp.Width, bmp.Height); // 源区域为整个位图
- for (int i = 0; i <= bmp.Width / 2; i += stepCount)
- {
- int j = i * bmp.Height / bmp.Width; // 计算高度变化量,如果宽度大,则高度变化量小于宽度,否则大于宽度
- Rectangle destRect = new Rectangle(bmp.Width / 2 - i, bmp.Height / 2 - j, 2 * i, 2 * j);
- dc.DrawImage(bmp, destRect, sourRect, GraphicsUnit.Pixel);
- ShowBmp(destRect);
- Thread.Sleep(10 * delay);
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 逐行分块
- // 原理:将图像分为正方形块,然后从左到右,从上到下顺序显示
- private void Animator05()
- {
- const float blockSize = 50; // 正方块的边长
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- // 防止最后一列、最后一行不足一块的尺寸而不显示,故采用上取整
- for (int y = 0; y < Math.Ceiling(bmp.Height / blockSize); y++)
- {
- for (int x = 0; x < Math.Ceiling(bmp.Width / blockSize); x++)
- {
- RectangleF rect;
- if (y % 2 == 0) // 从左到右
- {
- rect = new RectangleF(x * blockSize, y * blockSize, blockSize, blockSize);
- }
- else // 从右到左
- {
- rect = new RectangleF((bmp.Width / blockSize - x - 1) * blockSize, y * blockSize, blockSize, blockSize);
- }
- dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);
- ShowBmp(rect);
- Thread.Sleep(10 * delay);
- }
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 交替分块(改进版)
- // 原理:将图像分为正方形块,然后计算所有分块按照奇偶从左到右显示或从右到左显示所需的区域,并用材质画刷填充
- private void Animator06()
- {
- const float blockSize = 70; // 正方块的边长
- const int showWidth = 1; // 每次显示的像素列数
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- // 建立空区域,如使用Region的无参构造函数则建立一个无限大小的区域,而非空区域
- Region region = new Region(new GraphicsPath());
- // 建立位图材质画刷
- TextureBrush textureBrush = new TextureBrush(bmp);
- // 分块的行坐标+列坐标为偶数则从左到右逐列显示本块,否则从右到左逐列显示本块
- for (int i = 0; i <= Math.Ceiling(blockSize / showWidth); i++)
- {
- for (int x = 0; x < Math.Ceiling(bmp.Width / blockSize); x++)
- {
- for (int y = 0; y < Math.Ceiling(bmp.Height / blockSize); y++)
- {
- RectangleF rect;
- // 判断块的行列坐标和为奇数或偶数
- if ((x + y) % 2 == 0)
- {
- rect = new RectangleF(x * blockSize + i * showWidth, y * blockSize, showWidth, blockSize);
- }
- else
- {
- rect = new RectangleF((x + 1) * blockSize - i * showWidth, y * blockSize, showWidth, blockSize);
- }
- region.Union(rect); // 将要显示的区域合并到region中
- }
- }
- dc.FillRegion(textureBrush, region); // 使用材质画刷填充区域
- ShowBmp(region.GetBounds(dc));
- Thread.Sleep(10 * delay);
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 交叉竖条(改进版)
- // 原理:将图像分成宽度相等的列,然后计算从上下两个方向交叉前进的区域,并使用材质画刷填充
- private void Animator07()
- {
- const float lineWidth = 4; // 竖条宽度
- const float lineStep = 6; // 竖条每次前进的步长
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- GraphicsPath path = new GraphicsPath(); // 建立路径,路径处理速度要明显快于Region,但不支持集合运算
- TextureBrush textureBrush = new TextureBrush(bmp);
- // 从上到下和从下到上以步长为单位显示
- for (int y = 0; y < Math.Ceiling(bmp.Height / lineStep); y++)
- {
- // 显示两个方向的每个垂直竖条
- for (int x = 0; x < Math.Ceiling(bmp.Width / lineWidth); x++)
- {
- RectangleF rect;
- if (x % 2 == 0) // 从上到下
- {
- rect = new RectangleF(x * lineWidth, y * lineStep, lineWidth, lineStep);
- }
- else // 从下到上
- {
- rect = new RectangleF(x * lineWidth, bmp.Height - y * lineStep - lineStep, lineWidth, lineStep);
- }
- path.AddRectangle(rect);
- }
- dc.FillPath(textureBrush, path);
- ShowBmp(path.GetBounds());
- Thread.Sleep(10 * delay);
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 透明淡入(改进版)
- // 原理:使用ImageAttributes类和颜色转换矩阵处理图像,使每个像素的颜色分量同步增加
- private void Animator08()
- {
- const float stepCount = 0.02f; // 颜色转换矩阵增量,该值除1应等于整数
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- // ImageAttributes类的实例用于调整颜色,由DrawImage()方法调用
- ImageAttributes attributes = new ImageAttributes();
- // 建立5*5阶RGBA颜色矩阵
- ColorMatrix matrix = new ColorMatrix();
- float value = 0;
- while (value < 1f)
- {
- matrix.Matrix33 = value;
- // 为ImageAttributes对象指定颜色调整矩阵
- // ColorMatrixFlag.Default表示使用矩阵调整所有颜色;ColorAdjustType.Bitmap表示调整位图的颜色
- attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
- dc.Clear(Color.FromKnownColor(KnownColor.ButtonFace)); // 清空DC,否则每次会将不同的透明度图像叠加显示
- dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
- value += stepCount;
- ShowBmp();
- Thread.Sleep(10 * delay);
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 三色淡入
- // 原理:使用ImageAttributes类和颜色转换矩阵处理图像,分三次增加每个像素的单个颜色分量
- private void Animator09()
- {
- const float stepCount = 0.025f; // 颜色转换矩阵增量,该值除1应等于整数
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- // ImageAttributes类的实例用于调整颜色,由DrawImage()方法调用
- ImageAttributes attributes = new ImageAttributes();
- // 建立5*5阶RGBA颜色矩阵
- ColorMatrix matrix = new ColorMatrix();
- matrix.Matrix00 = 0f; // R为0
- matrix.Matrix11 = 0f; // G为0
- matrix.Matrix22 = 0f; // B为0
- // 以下三个循环依次处理B、R、G,符合亮度方程的原理
- // 人眼对B最不敏感,对G最敏感,或者说B传达的亮度信息最少,G传达的亮度信息最多
- // 因此先处理亮度信息少的,最后处理亮度信息多的,如果反过来处理,则变化不明显
- float value = 0f;
- while (value < 1f)
- {
- matrix.Matrix22 = value; // 颜色R的转换矩阵分量值
- // 为ImageAttributes对象指定颜色调整矩阵
- // ColorMatrixFlag.Default表示使用矩阵调整所有颜色;ColorAdjustType.Bitmap表示调整位图的颜色
- attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
- dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
- value += stepCount;
- ShowBmp();
- Thread.Sleep(10 * delay);
- }
- value = stepCount;
- while (value < 1f)
- {
- matrix.Matrix00 = value; // 颜色G的转换矩阵分量值
- attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
- dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
- value += stepCount;
- ShowBmp();
- Thread.Sleep(10 * delay);
- }
- value = stepCount;
- while (value < 1f)
- {
- matrix.Matrix11 = value; // 颜色B的转换矩阵分量值
- attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
- dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
- value += stepCount;
- ShowBmp();
- Thread.Sleep(10 * delay);
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
- #region 水平拉幕
- // 原理:由中心向开始逐渐输出中心两侧的像素,直到宽度为原始大小
- private void Animator10()
- {
- const int stepCount = 4; // 每次增加的步长像素,该值应能被宽度整除
- try
- {
- OnDrawStarted(this, EventArgs.Empty);
- ClearBackground();
- for (int i = 0; i <= Math.Ceiling(bmp.Width / 2f); i += stepCount)
- {
- Rectangle rect = new Rectangle(bmp.Width / 2 - i, 0, 2 * i, bmp.Height);
- dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);
- ShowBmp(rect);
- Thread.Sleep(10 * delay);
- }
- }
- catch (Exception ex)
- {
- ShowError(ex.Message);
- }
- finally
- {
- OnDrawCompleted(this, EventArgs.Empty);
- }
- }
- #endregion
本文的最后一部分(下),会附上完整的项目文件组,包含所有资源及可执行文件。
这里是本文的第二部分:http://mengliao.blog.51cto.com/876134/473193