WM中实现Splash动画效果
2009-09-14 08:08 老羽 阅读(1223) 评论(2) 收藏 举报通过一个Demo演示动画效果的Splash窗体,同时也是一个全屏的演示DEMO;动画效果通过切换不同的图片实现。类图如下:
(连线可能有问题,请指正,呵呵:)
实现思路:
1.SplashForm为动画效果展示窗体,通过线程Timer定时播放,播放的具体操作由接口ISplashStrategy完成;
2.主界面通过后台线程加载操作,保证Splash不会堵塞;
代码如下:
TestForm为主窗体,调用SplashForm,显示动画效果;
public partial class TestForm : BaseFullScreenForm { #region Fields private SplashScreen _splashScreen = null; #endregion public TestForm() { _splashScreen = new SplashScreen(new ImageSplashScreen()); _splashScreen.ShowFromOwner(this, 500); InitializeComponent(); } protected override void OnLoad(EventArgs e) { AsyncLoad(); } private void AsyncLoad() { ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncLoadInvoke)); } private void AsyncLoadInvoke(object target) { //do something //测试加载过程 for (int i = 0; i < 100; i++) { Thread.Sleep(50); } this.Invoke(new ThreadStart(CloseSplashInvoke)); } private void CloseSplashInvoke() { //_splashScreen.Close(); _splashScreen.Close(1000); //演示结束 this.Close(); } }
SplashScreen为Splash控制器,封装了调用、关闭与显示效果的操作;SplashScreen注册了SplashForm的两个事件:Paint与Ticks(自定义事件,由定时器触发),并通过接口ISplashStrategy实现背景与动画效果的展现;
public class SplashScreen : IDisposable { #region Fields private SplashForm _splashForm; private readonly object _lockDraw = new object(); private readonly object _lockSplashForm = new object(); private ISplashStrategy _splshStategy; private Graphics _graphics = null; #endregion public SplashScreen(ISplashStrategy splashStategy) { _splshStategy = splashStategy; } public void Close(int delay) { Thread.Sleep(delay); Close(); } public void Close() { if (_graphics != null) { _graphics.Dispose(); _graphics = null; } if (_splashForm != null) { _splashForm.Dispose(); _splashForm = null; } if (_splshStategy != null) { _splshStategy.Dispose(); _splshStategy = null; } } public void ShowFromOwner(Form parentForm, int speed) { SplashForm.Initialize(speed, parentForm); } private SplashForm SplashForm { get { if (_splashForm == null) { lock (this) { if (_splashForm == null) { _splashForm = CreateSplashForm(); } } } return _splashForm; } } private SplashForm CreateSplashForm() { SplashForm result = new SplashForm(); result.Paint += new PaintEventHandler(result_Paint); result.Ticks += new EventHandler(SplashForm_Ticks); return result; } void result_Paint(object sender, PaintEventArgs e) { if (this._splshStategy != null) { this._splshStategy.OnPaintBackground(Graphics); } } void SplashForm_Ticks(object sender, EventArgs e) { if (this._splshStategy != null) { this._splshStategy.OnTicks(Graphics); } } public Graphics Graphics { get { if (_graphics == null) { lock (_lockDraw) { if (_graphics == null) { _graphics = this.CreateGraphics(); } } } return _graphics; } } protected virtual Graphics CreateGraphics() { if (_splashForm != null && !_splashForm._isDisposed) { return _splashForm.CreateGraphics(); } return null; } #region IDisposable 成员 public void Dispose() { throw new NotImplementedException(); } #endregion }
SplashForm为具体的动画窗体,内置定时器,并定时抛出事件 Ticks;SplashForm继承BaseFullScreenForm,实现全屏的效果,实现全屏不是一定的,看需要,是否通过全屏展现动画效果;
internal partial class SplashForm : BaseFullScreenForm { #region Fileds private ThreadTimer _timer = null; internal bool _isDisposed = false; private bool _isInit = false; private bool _loaded = false; #endregion internal SplashForm() { } public void Initialize(int speed,Form parentForm) { CreateTimer(speed); //SetWindowLongPtr(this.Handle, GWL_HWNDPARENT, IntPtr.Zero); this.TopMost = true; this.Show(); //SetForegroundWindow(this.Handle); _isInit = true; //WaitForLoading(-1); } protected bool WaitForLoading(int millisecondsTimeout) { while (!_loaded) { Application.DoEvents(); Thread.Sleep(10); } return true; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (_isInit) { Start(); _isInit = false; _loaded = true; } } private void Start() { if (_timer != null) { _timer.Start(); } } private void CreateTimer(int speed) { if (_timer == null) { _timer = new ThreadTimer(0, speed); _timer.Tick += new EventHandler(Timer_Tick); } } private void Timer_Tick(object sender, EventArgs e) { try { OnTicks(e); } catch { } } [DllImport("Coredll.dll", EntryPoint = "SetWindowLong")] public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); public const int GWL_EXSTYLE = -20; public const int GWL_HWNDPARENT = -8; public const int GWL_ID = -12; public const int GWL_STYLE = -16; public const int GWL_WNDPROC = -4; #region Events public event EventHandler Ticks; protected virtual void OnTicks(EventArgs e) { if (Ticks != null) { Ticks(this, e); } } #endregion }
BaseFullScreenForm,封装了实现全屏的操作,重要的是两个地方:OnActivated与OnResize方法,如果不响应这两个方法,并设置全屏,会发现开始菜单栏屏蔽不了(网上很多代码没有这个,基本用不了);
public class BaseFullScreenForm : Form { public BaseFullScreenForm() { this.FormBorderStyle = FormBorderStyle.None; SetFullScreen(); } protected override void OnActivated(EventArgs e) { SetFullScreen(); base.OnActivated(e); } protected override void OnResize(EventArgs e) { SetFullScreen(); base.OnResize(e); } protected void SetFullScreen() { Rectangle rc = Screen.PrimaryScreen.Bounds; IntPtr hWnd = this.Handle; SHFullScreen(hWnd, SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON); MoveWindow(hWnd, rc.Left, rc.Top, rc.Width, rc.Height, true); //SetWindowPos(this.Handle, -1, 0, 0, 0, 0, SWP_NOSIZE | // SWP_NOMOVE | // SWP_FRAMECHANGED | // SWP_NOACTIVATE); } #region Mobile private const int SHFS_SHOWTASKBAR = 0x0001; private const int SHFS_HIDETASKBAR = 0x0002; private const int SHFS_SHOWSIPBUTTON = 0x0004; private const int SHFS_HIDESIPBUTTON = 0x0008; private const int SHFS_SHOWSTARTICON = 0x0010; private const int SHFS_HIDESTARTICON = 0x0020; [DllImport("aygshell.dll")] private static extern bool SHFullScreen(IntPtr hWnd, int dwState); [DllImport("coredll.dll")] public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int width, int height, bool repaint); [DllImport("coredll.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); [DllImport("coredll.dll")] public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int Flags); public const int SWP_NOSIZE = 0x0001; public const int SWP_NOMOVE = 0x0002; public const int SWP_NOZORDER = 0x0004; public const int SWP_NOREDRAW = 0x0008; public const int SWP_NOACTIVATE = 0x0010; public const int SWP_FRAMECHANGED = 0x0020; /* The frame changed: send WM_NCCALCSIZE */ public const int SWP_SHOWWINDOW = 0x0040; public const int SWP_HIDEWINDOW = 0x0080; public const int SWP_NOCOPYBITS = 0x0100; public const int SWP_NOOWNERZORDER = 0x0200;/* Don't do owner Z ordering */ public const int SWP_NOSENDCHANGING = 0x0400; /* Don't send WM_WINDOWPOSCHANGING */ public const int SWP_DRAWFRAME = SWP_FRAMECHANGED; public const int SWP_NOREPOSITION = SWP_NOOWNERZORDER; private static int MenuHeight = SystemInformation.MenuHeight; #endregion }
接口ISplashStrategy,抽象具体展现Splash的操作;
public interface ISplashStrategy : IDisposable { void OnPaintBackground(Graphics g); void OnTicks(Graphics g); }
ImageSplashScreen,实现接口ISplashStrategy,实现具体显示Splash效果的操作,这里就是切换图片
public class ImageSplashScreen : ISplashStrategy { #region Fields private int _index = 1; private string[] _images; #endregion public ImageSplashScreen() { _images = CreateImages(); if (_images == null && _images.Length == 0) { throw new ArgumentException("Splash图片不存在!"); } } #region ISplashStategy 成员 public void OnPaintBackground(System.Drawing.Graphics g) { g.DrawImage(ImageSplashScreen.FormFile(_images[0]), 0, 0); } public void OnTicks(System.Drawing.Graphics g) { int i = _index % _images.Length == 0 ? _images.Length - 1: _index % _images.Length; g.DrawImage(ImageSplashScreen.FormFile(_images[i]), 0, 0); _index++; } #endregion protected virtual string[] CreateImages() { string[] imgs = new string[3] { Path.Combine(ApplicationEx.StartupPath,"splash1.png"), Path.Combine(ApplicationEx.StartupPath,"splash2.png"), Path.Combine(ApplicationEx.StartupPath,"splash3.png") }; return imgs; } private static Image FormFile(string file) { Image result = null; if (File.Exists(file)) { using (FileStream input = new FileStream(file, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[(int)input.Length]; input.Read(buffer, 0, buffer.Length); MemoryStream m = new MemoryStream(buffer, 0, buffer.Length, false, true); try { result = new Bitmap(m); } finally { m.Close(); } } } return result; } #region IDisposable 成员 public void Dispose() { _images = null; } #endregion }
结束语
这个代码尚未考虑,如何展现进度条,如何展现文本提示,以后再发文实现。
作者:老羽(Michael-Zhangyu's Blog)
出处:http://michael-zhangyu.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。