genli

导航

QQ停靠方法2:

QQ停靠方法2:
 WindowsFormsApplication2.FormDockTemplate m_oDockFormTemplate = new FormDockTemplate(this);
您只需要在你的窗体初始化的时候(也就是窗体构造函数里添加上述这一行代码)您的程序就可以轻松拥有靠边自动隐藏的功能。
 具体方法步骤如下:
 1。右键解决方案,分别添加FormDockTemplate,FormStartInfo,User32这三个类,并且做些少许的改动代码分别如下:
(1)FormDockTemplate:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication2
{

    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.parentForm.Handle, ref rcFormClient);   
            Rectangle rcFormBound = new Rectangle(rcFormClient.left, rcFormClient.top, rcFormClient.right - rcFormClient.left, rcFormClient.bottom - rcFormClient.top);   
            return !rcFormBound.Contains(ptClientCursor);   
        }  
        #endregion   
    }   

(2)FormStartInfo类:这个类是负责隐藏或显示窗体,并计算其位置和保存窗体的大小及位置
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 WindowsFormsApplication2
{
    public enum Enu_FormDockStyle   
    {   
        None = 0,   
        Left = 1,   
        Top = 2,   
        Right = 3,   
        Bottom = 4,   
    }   
  
    [Serializable] 
    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;   
            }   
        }   
    }   

(3)User32类:此过程中引用的一些API函数:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication2
{
    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);   
    }   

 2,在你所要停靠的窗体的构造函数中添加这句代码:WindowsFormsApplication2.FormDockTemplate m_oDockFormTemplate = new FormDockTemplate(this);
你就可以实现将你所要停靠的窗体进行依靠了。而且可以解决二级窗体的停靠。更多级原理上也是可以的。

posted on 2011-02-08 21:00  genli  阅读(302)  评论(0)    收藏  举报