http://www.cnblogs.com/yechensi/archive/2009/08/02/1537145.html
你想过为自己的程序添加靠边隐藏的功能吗?还在为计算窗体的大小及位置而烦恼吗?想这么简单的轻松调用吗?
DockWindow.FormDockTemplate m_oDockFormTemplate = new DockWindow.FormDockTemplate(this);
不用吃惊,您只需要在你的窗体初始化的时候(也就是窗体构造函数里添加上述这一行代码)您的程序就可以轻松拥有靠边自动隐藏的功能。
下面我就给各位共享一个我自己经常用的靠边停靠的窗体类,详细见如下代码:
FormDockTemplate.cs文件:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Drawing;
- using System.Windows.Forms;
- namespace DockWindow
- {
- public class FormDockTemplate : NativeWindow
- {
- #region 私有字段
- /// <summary>
- /// 父级窗口实例
- /// </summary>
- private Form parentForm = null;
- /// <summary>
- /// 窗口实例的启动信息
- /// </summary>
- private FormStartInfo m_oFormStartInfo = null;
- /// <summary>
- /// 当前窗口可以停靠的方式
- /// </summary>
- private Enu_FormDockStyle m_iDockStyle = Enu_FormDockStyle.None;
- /// <summary>
- /// 窗口停靠检测的定时器
- /// </summary>
- private Timer m_tmrHideWindow = null;
- /// <summary>
- /// 自动感知的矩形区域
- /// </summary>
- private Rectangle m_rcLeft = Rectangle.Empty;
- private Rectangle m_rcTop = Rectangle.Empty;
- private Rectangle m_rcRight = Rectangle.Empty;
- private Rectangle m_rcBottom = Rectangle.Empty;
- /// <summary>
- /// 感知区域的容差值,也就是当鼠标移动进入距边缘几个象素时进行自动捕获
- /// </summary>
- private int m_iSensitiveAreaTolerantPixel = 4;
- #endregion
- #region 字段属性
- /// <summary>
- /// 当前窗口的鼠标位置
- /// </summary>
- Point CurrentMousePos
- {
- get
- {
- //获取当前鼠标的屏幕坐标
- User32.POINT ptMousePos = new User32.POINT();
- User32.GetCursorPos(ref ptMousePos);
- return new Point(ptMousePos.X, ptMousePos.Y);
- }
- }
- Rectangle FormTitleRect
- {
- get { return new Rectangle(parentForm.Location, new Size(parentForm.Width, parentForm.Height - parentForm.ClientRectangle.Height)); }
- }
- /// <summary>
- /// 感应区域的容差设置,距离屏幕边缘多少象素时,开始自动感知
- /// </summary>
- public int TolerantPixel
- {
- get { return m_iSensitiveAreaTolerantPixel; }
- set { m_iSensitiveAreaTolerantPixel = value; }
- }
- #endregion
- #region 构造函数
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="frmParent">父窗口对象</param>
- public FormDockTemplate(Form frmParent)
- : this(frmParent, 4)
- {
- }
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="frmParent">父窗口对象</param>
- /// <param name="iTolerantPixel">自动感知容差象素(当Mouse距离屏幕边缘多少象素时自动感知)</param>
- public FormDockTemplate(Form frmParent, int iTolerantPixel)
- {
- m_iSensitiveAreaTolerantPixel = iTolerantPixel;
- parentForm = frmParent;
- parentForm.HandleCreated += new EventHandler(parentForm_HandleCreated);
- parentForm.HandleDestroyed += new EventHandler(parentForm_HandleDestroyed);
- parentForm.Load += new EventHandler(parentForm_Load);
- parentForm.Move += new EventHandler(parentForm_Move);
- parentForm.Resize += new EventHandler(parentForm_Resize);
- //初始化窗体的启动信息:如上次关闭时窗体的大小及位置
- InitialFormStartInfo();
- }
- /// <summary>
- /// 初始化窗体启动信息,通过反序列化完成
- /// </summary>
- void InitialFormStartInfo()
- {
- try
- {
- m_oFormStartInfo = new FormStartInfo(parentForm);
- FormStartInfo.Deserialize(ref m_oFormStartInfo);
- }
- catch
- {
- m_oFormStartInfo.FormLocation = parentForm.Location;
- m_oFormStartInfo.FormSize = new Size(parentForm.Width, parentForm.Height);
- }
- }
- #endregion
- #region 窗体事件处理
- void parentForm_Load(object sender, EventArgs e)
- {
- //初始化感知区域
- InitialDockArea();
- //初始化时设置窗口大小及位置
- parentForm.Location = m_oFormStartInfo.FormLocation;
- parentForm.Size = m_oFormStartInfo.FormSize;
- //定时器初始化
- m_tmrHideWindow = new Timer();
- m_tmrHideWindow.Interval = 100;
- m_tmrHideWindow.Enabled = true;
- m_tmrHideWindow.Tick += new EventHandler(m_tmrHideWindow_Tick);
- }
- void parentForm_Resize(object sender, EventArgs e)
- {
- m_oFormStartInfo.FormSize = parentForm.Size;
- }
- void parentForm_Move(object sender, EventArgs e)
- {
- //当左键按下时并且当前鼠标位置处于窗口标题栏区域内,则认为是合法窗口移动,启用自动感知功能
- if (Control.MouseButtons == MouseButtons.Left && FormTitleRect.Contains(CurrentMousePos))
- {
- SetFormDockPos();
- }
- }
- void parentForm_HandleDestroyed(object sender, EventArgs e)
- {
- //销毁定时器
- m_tmrHideWindow.Enabled = false;
- m_tmrHideWindow.Stop();
- m_tmrHideWindow.Dispose();
- //窗口关闭时,保存窗口的大小位置及停靠信息
- if (m_iDockStyle == Enu_FormDockStyle.None)
- {
- m_oFormStartInfo.FormLocation = parentForm.Location;
- m_oFormStartInfo.FormSize = parentForm.Size;
- }
- FormStartInfo.Serialize(m_oFormStartInfo);
- //释放本类关联的窗口句柄
- ReleaseHandle();
- }
- void parentForm_HandleCreated(object sender, EventArgs e)
- {
- AssignHandle(((Form)sender).Handle);
- }
- void m_tmrHideWindow_Tick(object sender, EventArgs e)
- {
- if (m_oFormStartInfo.DockStyle != Enu_FormDockStyle.None)
- {
- //为了提升显示效率,只有处于如下两种情况时,才需要重新显示窗体
- //1、窗体可见但鼠标已经移出窗体外
- //2、窗体不可见但鼠标已经移入窗体内
- bool bNeedReshow = (m_oFormStartInfo.FormVisible && IsMouseOutForm()) ||
- (!m_oFormStartInfo.FormVisible && !IsMouseOutForm());
- if (bNeedReshow)
- m_oFormStartInfo.ShowDockWindow(parentForm.Handle, !IsMouseOutForm());
- }
- }
- #endregion
- #region 私有函数
- private void InitialDockArea()
- {
- //获取屏幕可用区域
- User32.RECT rectWorkArea = new User32.RECT();
- User32.SystemParametersInfo((uint)User32.Enu_SystemParametersInfo_Action.SPI_GETWORKAREA, 0, ref rectWorkArea, 0);
- Rectangle rcWorkArea = new Rectangle(rectWorkArea.left, rectWorkArea.top, rectWorkArea.right - rectWorkArea.left, rectWorkArea.bottom - rectWorkArea.top);
- Rectangle rcScreenArea = Screen.PrimaryScreen.Bounds;
- //容差值,表示鼠标移动到边界若干象素里即可以自动感知停靠位置
- m_rcLeft = new Rectangle(rcWorkArea.Left, rcWorkArea.Top, m_iSensitiveAreaTolerantPixel, rcWorkArea.Height);
- m_rcTop = new Rectangle(rcWorkArea.Left, rcWorkArea.Top, rcWorkArea.Width, m_iSensitiveAreaTolerantPixel);
- m_rcRight = new Rectangle(rcWorkArea.Width - rcWorkArea.Left - m_iSensitiveAreaTolerantPixel, rcWorkArea.Top, m_iSensitiveAreaTolerantPixel, rcWorkArea.Height);
- m_rcBottom = new Rectangle(rcScreenArea.Left, rcScreenArea.Bottom - rcScreenArea.Top - m_iSensitiveAreaTolerantPixel, rcScreenArea.Width, m_iSensitiveAreaTolerantPixel);
- }
- /// <summary>
- /// 鼠标按下时未放开的时候,设置窗体停靠时的位置
- /// </summary>
- void SetFormDockPos()
- {
- m_iDockStyle = Enu_FormDockStyle.None;
- //根据不同的停靠方式来重置窗体位置
- if (m_rcLeft.Contains(CurrentMousePos))
- {
- parentForm.Location = m_rcLeft.Location;
- parentForm.Height = m_rcLeft.Height;
- m_iDockStyle = Enu_FormDockStyle.Left;
- }
- else if (m_rcTop.Contains(CurrentMousePos))
- {
- parentForm.Location = new Point(parentForm.Location.X, m_rcTop.Top);
- m_iDockStyle = Enu_FormDockStyle.Top;
- }
- else if (m_rcRight.Contains(CurrentMousePos))
- {
- parentForm.Location = new Point(m_rcRight.Right - parentForm.Width, m_rcRight.Top);
- parentForm.Height = m_rcRight.Height;
- m_iDockStyle = Enu_FormDockStyle.Right;
- }
- else if (m_rcBottom.Contains(CurrentMousePos))
- {
- parentForm.Location = new Point(parentForm.Location.X, m_rcBottom.Bottom - parentForm.Height);
- m_iDockStyle = Enu_FormDockStyle.Bottom;
- }
- m_oFormStartInfo.DockStyle = m_iDockStyle;
- m_oFormStartInfo.FormLocation = parentForm.Location;
- }
- /// <summary>
- /// 表明当前鼠标位置是否已经移出窗体外
- /// </summary>
- /// <returns></returns>
- private bool IsMouseOutForm()
- {
- //获取当前鼠标的屏幕坐标
- User32.POINT ptMousePos = new User32.POINT();
- User32.GetCursorPos(ref ptMousePos);
- Point ptClientCursor = new Point(ptMousePos.X, ptMousePos.Y);
- User32.RECT rcFormClient = new User32.RECT();
- User32.GetWindowRect(this.Handle, ref rcFormClient);
- Rectangle rcFormBound = new Rectangle(rcFormClient.left, rcFormClient.top, rcFormClient.right - rcFormClient.left, rcFormClient.bottom - rcFormClient.top);
- return !rcFormBound.Contains(ptClientCursor);
- }
- #endregion
- }
- }
下面这个类是负责隐藏或显示窗体,并计算其位置和保存窗体的大小及位置
FormStartInfo.cs 文件:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.IO;
- using System.Drawing;
- using System.Runtime.Serialization;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.Windows.Forms;
- namespace DockWindow
- {
- public enum Enu_FormDockStyle
- {
- None = 0,
- Left = 1,
- Top = 2,
- Right = 3,
- Bottom = 4,
- }
- [Serializable]
- public class FormStartInfo
- {
- [NonSerialized]
- private Form m_frmDockWindow = null;
- private string m_strSerialFileName = string.Empty;
- private Size m_szFormSize = Size.Empty;
- private Point m_ptFormLocation = Point.Empty;
- private Enu_FormDockStyle m_iDockStyle = Enu_FormDockStyle.None;
- private bool m_bFormVisible = false;
- /// <summary>
- /// 构造函数
- /// </summary>
- /// <param name="frmItem">停靠的窗体对象</param>
- public FormStartInfo(Form frmItem)
- {
- try
- {
- m_frmDockWindow = frmItem;
- if (null == frmItem) m_strSerialFileName = "StartInfo.dat";
- else m_strSerialFileName = frmItem.Name + frmItem.Text + "_StartInfo.dat";
- }
- catch { }
- }
- /// <summary>
- /// 窗体大小
- /// </summary>
- public Size FormSize
- {
- get { return m_szFormSize; }
- internal set { m_szFormSize = value; }
- }
- /// <summary>
- /// 窗体位置坐标
- /// </summary>
- public Point FormLocation
- {
- get { return m_ptFormLocation; }
- internal set { m_ptFormLocation = value; }
- }
- /// <summary>
- /// 停靠方式
- /// </summary>
- public Enu_FormDockStyle DockStyle
- {
- get { return m_iDockStyle; }
- internal set { m_iDockStyle = value; }
- }
- /// <summary>
- /// 表示窗体是否自动隐藏
- /// </summary>
- public bool FormVisible
- {
- get { return m_bFormVisible; }
- }
- /// <summary>
- /// 序列化此类的实例信息
- /// </summary>
- /// <param name="frmStartInfo"></param>
- public static void Serialize(FormStartInfo frmStartInfo)
- {
- using (FileStream fs = new FileStream(frmStartInfo.m_strSerialFileName, FileMode.OpenOrCreate))
- {
- BinaryFormatter bf = new BinaryFormatter();
- bf.Serialize(fs, frmStartInfo);
- }
- }
- /// <summary>
- /// 反序列化此类的实例信息
- /// </summary>
- /// <param name="frmStartInfo"></param>
- public static void Deserialize(ref FormStartInfo frmStartInfo)
- {
- FormStartInfo frmTemp = null;
- if (null == frmStartInfo) return;
- using (FileStream fs = new FileStream(frmStartInfo.m_strSerialFileName, FileMode.Open))
- {
- BinaryFormatter bf = new BinaryFormatter();
- frmTemp = (FormStartInfo)bf.Deserialize(fs);
- if (null != frmTemp) frmStartInfo = frmTemp;
- }
- }
- /// <summary>
- /// 显示或隐藏停靠窗口
- /// </summary>
- public void ShowDockWindow(IntPtr hwnd, bool bVisible)
- {
- Point ptLocation = Point.Empty;
- Size szFormSize = Size.Empty;
- m_bFormVisible = bVisible;
- if (m_frmDockWindow == null) m_frmDockWindow = (Form)Control.FromHandle(hwnd);
- if (m_frmDockWindow == null) return;
- GetDockWindowClientRect(ref ptLocation, ref szFormSize, bVisible);
- m_frmDockWindow.TopMost = (m_iDockStyle != Enu_FormDockStyle.None);
- m_frmDockWindow.Location = ptLocation;
- m_frmDockWindow.Width = szFormSize.Width;
- m_frmDockWindow.Height = szFormSize.Height;
- }
- /// <summary>
- /// 根据当前窗体的停靠方式来计算出当前窗体的大小及位置
- /// </summary>
- /// <param name="ptLocation">窗体位置</param>
- /// <param name="szFormSize">窗体大小</param>
- /// <param name="bDockWindowVisible">显示还是隐藏</param>
- private void GetDockWindowClientRect(ref Point ptLocation, ref Size szFormSize, bool bDockWindowVisible)
- {
- int iTorrentPixel = 0;
- int iWindowTitleHeight = SystemInformation.CaptionHeight;
- //获取屏幕可用区域
- User32.RECT rectWorkArea = new User32.RECT();
- User32.SystemParametersInfo((uint)User32.Enu_SystemParametersInfo_Action.SPI_GETWORKAREA, 0, ref rectWorkArea, 0);
- Rectangle rcWorkArea = new Rectangle(rectWorkArea.left, rectWorkArea.top, rectWorkArea.right - rectWorkArea.left, rectWorkArea.bottom - rectWorkArea.top);
- Rectangle rcScreenArea = Screen.PrimaryScreen.Bounds;
- if (m_ptFormLocation.X < 0) m_ptFormLocation.X = 0;
- if (m_ptFormLocation.Y < 0) m_ptFormLocation.Y = 0;
- if (!bDockWindowVisible)
- {
- switch (m_iDockStyle)
- {
- case Enu_FormDockStyle.None:
- ptLocation = m_ptFormLocation;
- szFormSize = m_szFormSize;
- break;
- case Enu_FormDockStyle.Left:
- ptLocation = new Point(m_ptFormLocation.X - m_szFormSize.Width + SystemInformation.FrameBorderSize.Width + iTorrentPixel, rcWorkArea.Top);
- szFormSize = new Size(m_szFormSize.Width, rcWorkArea.Height);
- break;
- case Enu_FormDockStyle.Top:
- ptLocation = new Point(m_ptFormLocation.X, rcWorkArea.Top - m_szFormSize.Height +SystemInformation.FrameBorderSize.Width + iTorrentPixel);
- szFormSize = m_szFormSize;
- break;
- case Enu_FormDockStyle.Right:
- ptLocation = new Point(rcWorkArea.Width - rcWorkArea.Left - SystemInformation.FrameBorderSize.Width - iTorrentPixel, rcWorkArea.Top);
- szFormSize = new Size(m_szFormSize.Width, rcWorkArea.Height);
- break;
- case Enu_FormDockStyle.Bottom:
- ptLocation = new Point(m_ptFormLocation.X, rcScreenArea.Bottom - rcScreenArea.Top - SystemInformation.FrameBorderSize.Width - iTorrentPixel);
- szFormSize = m_szFormSize;
- break;
- default:
- ptLocation = m_ptFormLocation;
- szFormSize = m_szFormSize;
- break;
- }
- }
- else
- {
- ptLocation = m_ptFormLocation;
- szFormSize = m_szFormSize;
- }
- }
- }
- }
下面在贴上在此过程中引用的一些API函数:
User32.cs文件:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Runtime.InteropServices;
- namespace DockWindow
- {
- class User32
- {
- [StructLayout(LayoutKind.Sequential)]
- public struct POINT
- {
- public int X;
- public int Y;
- }
- [StructLayout(LayoutKind.Sequential)]
- public struct RECT
- {
- public int left;
- public int top;
- public int right;
- public int bottom;
- }
- public enum Enu_SystemParametersInfo_Action
- {
- SPI_GETWORKAREA = 0x0030
- }
- [DllImport("User32.dll")]
- public static extern bool GetCursorPos(ref POINT lpPoint);
- [DllImport("User32.dll")]
- public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref RECT lpRect, uint fWinIni);
- [DllImport("User32.dll")]
- public static extern bool GetWindowRect(IntPtr hwnd, ref RECT lpRect);
- }
- }