zoukankan      html  css  js  c++  java
  • C#如何实现类似QQ那样靠边隐藏的功能

    http://www.cnblogs.com/yechensi/archive/2009/08/02/1537145.html

    C#如何实现类似QQ那样靠边隐藏的功能

    你想过为自己的程序添加靠边隐藏的功能吗?还在为计算窗体的大小及位置而烦恼吗?想这么简单的轻松调用吗?

    DockWindow.FormDockTemplate m_oDockFormTemplate = new DockWindow.FormDockTemplate(this);

    不用吃惊,您只需要在你的窗体初始化的时候(也就是窗体构造函数里添加上述这一行代码)您的程序就可以轻松拥有靠边自动隐藏的功能。

    下面我就给各位共享一个我自己经常用的靠边停靠的窗体类,详细见如下代码:

    FormDockTemplate.cs文件:

    1. using System;    
    2. using System.Collections.Generic;    
    3. using System.Text;    
    4. using System.Drawing;    
    5. using System.Windows.Forms;    
    6.   
    7. namespace DockWindow   
    8. {   
    9.     public class FormDockTemplate : NativeWindow   
    10.     {  
    11.         #region 私有字段   
    12.         /// <summary>    
    13.         /// 父级窗口实例    
    14.         /// </summary>    
    15.         private Form parentForm = null;   
    16.         /// <summary>    
    17.         /// 窗口实例的启动信息    
    18.         /// </summary>    
    19.         private FormStartInfo m_oFormStartInfo = null;   
    20.         /// <summary>    
    21.         /// 当前窗口可以停靠的方式    
    22.         /// </summary>    
    23.         private Enu_FormDockStyle m_iDockStyle = Enu_FormDockStyle.None;   
    24.         /// <summary>    
    25.         /// 窗口停靠检测的定时器    
    26.         /// </summary>    
    27.         private Timer m_tmrHideWindow = null;   
    28.         /// <summary>    
    29.         /// 自动感知的矩形区域    
    30.         /// </summary>    
    31.         private Rectangle m_rcLeft = Rectangle.Empty;   
    32.         private Rectangle m_rcTop = Rectangle.Empty;   
    33.         private Rectangle m_rcRight = Rectangle.Empty;   
    34.         private Rectangle m_rcBottom = Rectangle.Empty;   
    35.         /// <summary>    
    36.         /// 感知区域的容差值,也就是当鼠标移动进入距边缘几个象素时进行自动捕获    
    37.         /// </summary>    
    38.         private int m_iSensitiveAreaTolerantPixel = 4;  
    39.         #endregion  
    40.  
    41.         #region 字段属性   
    42.         /// <summary>    
    43.         /// 当前窗口的鼠标位置    
    44.         /// </summary>    
    45.         Point CurrentMousePos   
    46.         {   
    47.             get  
    48.             {   
    49.                 //获取当前鼠标的屏幕坐标               
    50.                 User32.POINT ptMousePos = new User32.POINT();   
    51.                 User32.GetCursorPos(ref ptMousePos);   
    52.                 return new Point(ptMousePos.X, ptMousePos.Y);   
    53.             }   
    54.         }   
    55.   
    56.         Rectangle FormTitleRect   
    57.         {   
    58.             get { return new Rectangle(parentForm.Location, new Size(parentForm.Width, parentForm.Height - parentForm.ClientRectangle.Height)); }   
    59.         }   
    60.   
    61.         /// <summary>    
    62.         /// 感应区域的容差设置,距离屏幕边缘多少象素时,开始自动感知    
    63.         /// </summary>    
    64.         public int TolerantPixel   
    65.         {   
    66.             get { return m_iSensitiveAreaTolerantPixel; }   
    67.             set { m_iSensitiveAreaTolerantPixel = value; }   
    68.         }  
    69.         #endregion  
    70.  
    71.         #region 构造函数   
    72.         /// <summary>    
    73.         /// 构造函数    
    74.         /// </summary>    
    75.         /// <param name="frmParent">父窗口对象</param>    
    76.         public FormDockTemplate(Form frmParent)   
    77.             : this(frmParent, 4)   
    78.         {   
    79.         }   
    80.   
    81.         /// <summary>    
    82.         /// 构造函数    
    83.         /// </summary>    
    84.         /// <param name="frmParent">父窗口对象</param>    
    85.         /// <param name="iTolerantPixel">自动感知容差象素(当Mouse距离屏幕边缘多少象素时自动感知)</param>    
    86.         public FormDockTemplate(Form frmParent, int iTolerantPixel)   
    87.         {   
    88.             m_iSensitiveAreaTolerantPixel = iTolerantPixel;   
    89.             parentForm = frmParent;   
    90.             parentForm.HandleCreated += new EventHandler(parentForm_HandleCreated);   
    91.             parentForm.HandleDestroyed += new EventHandler(parentForm_HandleDestroyed);   
    92.             parentForm.Load += new EventHandler(parentForm_Load);   
    93.             parentForm.Move += new EventHandler(parentForm_Move);               
    94.             parentForm.Resize += new EventHandler(parentForm_Resize);   
    95.   
    96.             //初始化窗体的启动信息:如上次关闭时窗体的大小及位置    
    97.             InitialFormStartInfo();   
    98.         }   
    99.   
    100.         /// <summary>   
    101.         /// 初始化窗体启动信息,通过反序列化完成   
    102.         /// </summary>   
    103.         void InitialFormStartInfo()   
    104.         {   
    105.             try  
    106.             {   
    107.                 m_oFormStartInfo = new FormStartInfo(parentForm);   
    108.                 FormStartInfo.Deserialize(ref m_oFormStartInfo);                   
    109.             }   
    110.             catch  
    111.             {   
    112.                 m_oFormStartInfo.FormLocation = parentForm.Location;   
    113.                 m_oFormStartInfo.FormSize = new Size(parentForm.Width, parentForm.Height);   
    114.             }   
    115.         }  
    116.         #endregion  
    117.  
    118.         #region 窗体事件处理   
    119.         void parentForm_Load(object sender, EventArgs e)   
    120.         {   
    121.             //初始化感知区域    
    122.             InitialDockArea();   
    123.   
    124.             //初始化时设置窗口大小及位置   
    125.             parentForm.Location = m_oFormStartInfo.FormLocation;   
    126.             parentForm.Size = m_oFormStartInfo.FormSize;   
    127.   
    128.             //定时器初始化    
    129.             m_tmrHideWindow = new Timer();   
    130.             m_tmrHideWindow.Interval = 100;   
    131.             m_tmrHideWindow.Enabled = true;   
    132.             m_tmrHideWindow.Tick += new EventHandler(m_tmrHideWindow_Tick);   
    133.         }   
    134.   
    135.         void parentForm_Resize(object sender, EventArgs e)   
    136.         {   
    137.             m_oFormStartInfo.FormSize = parentForm.Size;   
    138.         }   
    139.   
    140.         void parentForm_Move(object sender, EventArgs e)   
    141.         {   
    142.             //当左键按下时并且当前鼠标位置处于窗口标题栏区域内,则认为是合法窗口移动,启用自动感知功能    
    143.             if (Control.MouseButtons == MouseButtons.Left && FormTitleRect.Contains(CurrentMousePos))   
    144.             {   
    145.                 SetFormDockPos();                   
    146.             }   
    147.         }   
    148.           
    149.         void parentForm_HandleDestroyed(object sender, EventArgs e)   
    150.         {   
    151.             //销毁定时器    
    152.             m_tmrHideWindow.Enabled = false;   
    153.             m_tmrHideWindow.Stop();   
    154.             m_tmrHideWindow.Dispose();   
    155.   
    156.             //窗口关闭时,保存窗口的大小位置及停靠信息    
    157.             if (m_iDockStyle == Enu_FormDockStyle.None)   
    158.             {   
    159.                 m_oFormStartInfo.FormLocation = parentForm.Location;   
    160.                 m_oFormStartInfo.FormSize = parentForm.Size;   
    161.             }   
    162.             FormStartInfo.Serialize(m_oFormStartInfo);   
    163.   
    164.             //释放本类关联的窗口句柄    
    165.             ReleaseHandle();   
    166.         }   
    167.   
    168.         void parentForm_HandleCreated(object sender, EventArgs e)   
    169.         {   
    170.             AssignHandle(((Form)sender).Handle);   
    171.         }   
    172.   
    173.         void m_tmrHideWindow_Tick(object sender, EventArgs e)   
    174.         {   
    175.             if (m_oFormStartInfo.DockStyle != Enu_FormDockStyle.None)   
    176.             {   
    177.                 //为了提升显示效率,只有处于如下两种情况时,才需要重新显示窗体    
    178.                 //1、窗体可见但鼠标已经移出窗体外    
    179.                 //2、窗体不可见但鼠标已经移入窗体内    
    180.                 bool bNeedReshow = (m_oFormStartInfo.FormVisible && IsMouseOutForm()) ||   
    181.                     (!m_oFormStartInfo.FormVisible && !IsMouseOutForm());   
    182.                 if (bNeedReshow)   
    183.                     m_oFormStartInfo.ShowDockWindow(parentForm.Handle, !IsMouseOutForm());   
    184.             }   
    185.         }  
    186.         #endregion  
    187.  
    188.         #region 私有函数   
    189.         private void InitialDockArea()   
    190.         {   
    191.             //获取屏幕可用区域                
    192.             User32.RECT rectWorkArea = new User32.RECT();   
    193.             User32.SystemParametersInfo((uint)User32.Enu_SystemParametersInfo_Action.SPI_GETWORKAREA, 0, ref rectWorkArea, 0);   
    194.             Rectangle rcWorkArea = new Rectangle(rectWorkArea.left, rectWorkArea.top, rectWorkArea.right - rectWorkArea.left, rectWorkArea.bottom - rectWorkArea.top);   
    195.             Rectangle rcScreenArea = Screen.PrimaryScreen.Bounds;   
    196.   
    197.             //容差值,表示鼠标移动到边界若干象素里即可以自动感知停靠位置                
    198.             m_rcLeft = new Rectangle(rcWorkArea.Left, rcWorkArea.Top, m_iSensitiveAreaTolerantPixel, rcWorkArea.Height);   
    199.             m_rcTop = new Rectangle(rcWorkArea.Left, rcWorkArea.Top, rcWorkArea.Width, m_iSensitiveAreaTolerantPixel);   
    200.             m_rcRight = new Rectangle(rcWorkArea.Width - rcWorkArea.Left - m_iSensitiveAreaTolerantPixel, rcWorkArea.Top, m_iSensitiveAreaTolerantPixel, rcWorkArea.Height);   
    201.             m_rcBottom = new Rectangle(rcScreenArea.Left, rcScreenArea.Bottom - rcScreenArea.Top - m_iSensitiveAreaTolerantPixel, rcScreenArea.Width, m_iSensitiveAreaTolerantPixel);   
    202.         }   
    203.            
    204.         /// <summary>    
    205.         /// 鼠标按下时未放开的时候,设置窗体停靠时的位置    
    206.         /// </summary>    
    207.         void SetFormDockPos()   
    208.         {   
    209.             m_iDockStyle = Enu_FormDockStyle.None;   
    210.   
    211.             //根据不同的停靠方式来重置窗体位置    
    212.             if (m_rcLeft.Contains(CurrentMousePos))   
    213.             {   
    214.                 parentForm.Location = m_rcLeft.Location;   
    215.                 parentForm.Height = m_rcLeft.Height;   
    216.   
    217.                 m_iDockStyle = Enu_FormDockStyle.Left;   
    218.             }   
    219.             else if (m_rcTop.Contains(CurrentMousePos))   
    220.             {   
    221.                 parentForm.Location = new Point(parentForm.Location.X, m_rcTop.Top);   
    222.   
    223.                 m_iDockStyle = Enu_FormDockStyle.Top;   
    224.             }   
    225.             else if (m_rcRight.Contains(CurrentMousePos))   
    226.             {   
    227.                 parentForm.Location = new Point(m_rcRight.Right - parentForm.Width, m_rcRight.Top);   
    228.                 parentForm.Height = m_rcRight.Height;   
    229.   
    230.                 m_iDockStyle = Enu_FormDockStyle.Right;   
    231.             }   
    232.             else if (m_rcBottom.Contains(CurrentMousePos))   
    233.             {   
    234.                 parentForm.Location = new Point(parentForm.Location.X, m_rcBottom.Bottom - parentForm.Height);   
    235.   
    236.                 m_iDockStyle = Enu_FormDockStyle.Bottom;   
    237.             }   
    238.   
    239.             m_oFormStartInfo.DockStyle = m_iDockStyle;   
    240.             m_oFormStartInfo.FormLocation = parentForm.Location;               
    241.         }   
    242.   
    243.         /// <summary>    
    244.         /// 表明当前鼠标位置是否已经移出窗体外    
    245.         /// </summary>    
    246.         /// <returns></returns>    
    247.         private bool IsMouseOutForm()   
    248.         {   
    249.             //获取当前鼠标的屏幕坐标               
    250.             User32.POINT ptMousePos = new User32.POINT();   
    251.             User32.GetCursorPos(ref ptMousePos);   
    252.             Point ptClientCursor = new Point(ptMousePos.X, ptMousePos.Y);   
    253.   
    254.             User32.RECT rcFormClient = new User32.RECT();   
    255.             User32.GetWindowRect(this.Handle, ref rcFormClient);   
    256.             Rectangle rcFormBound = new Rectangle(rcFormClient.left, rcFormClient.top, rcFormClient.right - rcFormClient.left, rcFormClient.bottom - rcFormClient.top);   
    257.             return !rcFormBound.Contains(ptClientCursor);   
    258.         }  
    259.         #endregion   
    260.     }   
    261. }  

    下面这个类是负责隐藏或显示窗体,并计算其位置和保存窗体的大小及位置

    FormStartInfo.cs 文件:

    1. using System;    
    2. using System.Collections.Generic;    
    3. using System.Text;    
    4. using System.IO;    
    5. using System.Drawing;    
    6. using System.Runtime.Serialization;    
    7. using System.Runtime.Serialization.Formatters.Binary;    
    8. using System.Windows.Forms;    
    9.   
    10. namespace DockWindow   
    11. {   
    12.     public enum Enu_FormDockStyle   
    13.     {   
    14.         None = 0,   
    15.         Left = 1,   
    16.         Top = 2,   
    17.         Right = 3,   
    18.         Bottom = 4,   
    19.     }   
    20.   
    21.     [Serializable]   
    22.     public class FormStartInfo   
    23.     {   
    24.         [NonSerialized]   
    25.         private Form m_frmDockWindow = null;   
    26.         private string m_strSerialFileName = string.Empty;   
    27.         private Size m_szFormSize = Size.Empty;   
    28.         private Point m_ptFormLocation = Point.Empty;   
    29.         private Enu_FormDockStyle m_iDockStyle = Enu_FormDockStyle.None;   
    30.         private bool m_bFormVisible = false;   
    31.   
    32.   
    33.         /// <summary>    
    34.         /// 构造函数    
    35.         /// </summary>    
    36.         /// <param name="frmItem">停靠的窗体对象</param>    
    37.         public FormStartInfo(Form frmItem)   
    38.         {   
    39.             try  
    40.             {   
    41.                 m_frmDockWindow = frmItem;   
    42.   
    43.                 if (null == frmItem) m_strSerialFileName = "StartInfo.dat";   
    44.                 else m_strSerialFileName = frmItem.Name + frmItem.Text + "_StartInfo.dat";   
    45.             }   
    46.             catch { }   
    47.         }   
    48.   
    49.         /// <summary>    
    50.         /// 窗体大小    
    51.         /// </summary>    
    52.         public Size FormSize   
    53.         {   
    54.             get { return m_szFormSize; }   
    55.             internal set { m_szFormSize = value; }   
    56.         }   
    57.   
    58.         /// <summary>    
    59.         /// 窗体位置坐标    
    60.         /// </summary>    
    61.         public Point FormLocation   
    62.         {   
    63.             get { return m_ptFormLocation; }   
    64.             internal set { m_ptFormLocation = value; }   
    65.         }   
    66.   
    67.         /// <summary>    
    68.         /// 停靠方式    
    69.         /// </summary>    
    70.         public Enu_FormDockStyle DockStyle   
    71.         {   
    72.             get { return m_iDockStyle; }   
    73.             internal set { m_iDockStyle = value; }   
    74.         }   
    75.   
    76.         /// <summary>    
    77.         /// 表示窗体是否自动隐藏    
    78.         /// </summary>    
    79.         public bool FormVisible   
    80.         {   
    81.             get { return m_bFormVisible; }   
    82.         }   
    83.         /// <summary>    
    84.         /// 序列化此类的实例信息    
    85.         /// </summary>    
    86.         /// <param name="frmStartInfo"></param>    
    87.         public static void Serialize(FormStartInfo frmStartInfo)   
    88.         {   
    89.             using (FileStream fs = new FileStream(frmStartInfo.m_strSerialFileName, FileMode.OpenOrCreate))   
    90.             {   
    91.                 BinaryFormatter bf = new BinaryFormatter();   
    92.                 bf.Serialize(fs, frmStartInfo);   
    93.             }   
    94.         }   
    95.   
    96.         /// <summary>    
    97.         /// 反序列化此类的实例信息    
    98.         /// </summary>    
    99.         /// <param name="frmStartInfo"></param>    
    100.         public static void Deserialize(ref FormStartInfo frmStartInfo)   
    101.         {   
    102.             FormStartInfo frmTemp = null;   
    103.   
    104.             if (null == frmStartInfo) return;   
    105.             using (FileStream fs = new FileStream(frmStartInfo.m_strSerialFileName, FileMode.Open))   
    106.             {   
    107.                 BinaryFormatter bf = new BinaryFormatter();   
    108.                 frmTemp = (FormStartInfo)bf.Deserialize(fs);   
    109.                 if (null != frmTemp) frmStartInfo = frmTemp;   
    110.             }   
    111.         }   
    112.         /// <summary>    
    113.         /// 显示或隐藏停靠窗口    
    114.         /// </summary>    
    115.         public void ShowDockWindow(IntPtr hwnd, bool bVisible)   
    116.         {   
    117.             Point ptLocation = Point.Empty;   
    118.             Size szFormSize = Size.Empty;   
    119.   
    120.             m_bFormVisible = bVisible;   
    121.   
    122.             if (m_frmDockWindow == null) m_frmDockWindow = (Form)Control.FromHandle(hwnd);   
    123.             if (m_frmDockWindow == null) return;   
    124.   
    125.   
    126.   
    127.             GetDockWindowClientRect(ref ptLocation, ref szFormSize, bVisible);   
    128.   
    129.             m_frmDockWindow.TopMost = (m_iDockStyle != Enu_FormDockStyle.None);   
    130.             m_frmDockWindow.Location = ptLocation;   
    131.             m_frmDockWindow.Width = szFormSize.Width;   
    132.             m_frmDockWindow.Height = szFormSize.Height;   
    133.         }   
    134.         /// <summary>    
    135.         /// 根据当前窗体的停靠方式来计算出当前窗体的大小及位置    
    136.         /// </summary>    
    137.         /// <param name="ptLocation">窗体位置</param>    
    138.         /// <param name="szFormSize">窗体大小</param>    
    139.         /// <param name="bDockWindowVisible">显示还是隐藏</param>    
    140.         private void GetDockWindowClientRect(ref Point ptLocation, ref Size szFormSize, bool bDockWindowVisible)   
    141.         {   
    142.             int iTorrentPixel = 0;   
    143.             int iWindowTitleHeight = SystemInformation.CaptionHeight;   
    144.   
    145.   
    146.             //获取屏幕可用区域                
    147.             User32.RECT rectWorkArea = new User32.RECT();   
    148.             User32.SystemParametersInfo((uint)User32.Enu_SystemParametersInfo_Action.SPI_GETWORKAREA, 0, ref rectWorkArea, 0);   
    149.             Rectangle rcWorkArea = new Rectangle(rectWorkArea.left, rectWorkArea.top, rectWorkArea.right - rectWorkArea.left, rectWorkArea.bottom - rectWorkArea.top);   
    150.             Rectangle rcScreenArea = Screen.PrimaryScreen.Bounds;   
    151.   
    152.             if (m_ptFormLocation.X < 0) m_ptFormLocation.X = 0;   
    153.             if (m_ptFormLocation.Y < 0) m_ptFormLocation.Y = 0;   
    154.   
    155.             if (!bDockWindowVisible)   
    156.             {   
    157.                 switch (m_iDockStyle)   
    158.                 {   
    159.                     case Enu_FormDockStyle.None:   
    160.                         ptLocation = m_ptFormLocation;   
    161.                         szFormSize = m_szFormSize;   
    162.                         break;   
    163.                     case Enu_FormDockStyle.Left:   
    164.                         ptLocation = new Point(m_ptFormLocation.X - m_szFormSize.Width + SystemInformation.FrameBorderSize.Width + iTorrentPixel, rcWorkArea.Top);   
    165.                         szFormSize = new Size(m_szFormSize.Width, rcWorkArea.Height);   
    166.                         break;   
    167.                     case Enu_FormDockStyle.Top:   
    168.                         ptLocation = new Point(m_ptFormLocation.X, rcWorkArea.Top - m_szFormSize.Height +SystemInformation.FrameBorderSize.Width + iTorrentPixel);   
    169.                         szFormSize = m_szFormSize;   
    170.                         break;   
    171.                     case Enu_FormDockStyle.Right:   
    172.                         ptLocation = new Point(rcWorkArea.Width - rcWorkArea.Left - SystemInformation.FrameBorderSize.Width - iTorrentPixel, rcWorkArea.Top);   
    173.                         szFormSize = new Size(m_szFormSize.Width, rcWorkArea.Height);   
    174.                         break;   
    175.                     case Enu_FormDockStyle.Bottom:   
    176.                         ptLocation = new Point(m_ptFormLocation.X, rcScreenArea.Bottom - rcScreenArea.Top - SystemInformation.FrameBorderSize.Width - iTorrentPixel);   
    177.                         szFormSize = m_szFormSize;   
    178.                         break;   
    179.                     default:   
    180.                         ptLocation = m_ptFormLocation;   
    181.                         szFormSize = m_szFormSize;   
    182.                         break;   
    183.                 }   
    184.             }   
    185.             else  
    186.             {   
    187.                 ptLocation = m_ptFormLocation;   
    188.                 szFormSize = m_szFormSize;   
    189.             }   
    190.         }   
    191.     }   
    192. }  

    下面在贴上在此过程中引用的一些API函数:

    User32.cs文件:

    1. using System;   
    2. using System.Collections.Generic;   
    3. using System.Linq;   
    4. using System.Text;   
    5. using System.Runtime.InteropServices;   
    6.   
    7. namespace DockWindow   
    8. {   
    9.     class User32   
    10.     {   
    11.         [StructLayout(LayoutKind.Sequential)]   
    12.         public struct POINT   
    13.         {   
    14.             public int X;   
    15.             public int Y;   
    16.         }   
    17.   
    18.         [StructLayout(LayoutKind.Sequential)]   
    19.         public struct RECT   
    20.         {   
    21.             public int left;   
    22.             public int top;   
    23.             public int right;   
    24.             public int bottom;    
    25.         }   
    26.   
    27.         public enum Enu_SystemParametersInfo_Action   
    28.         {   
    29.             SPI_GETWORKAREA = 0x0030   
    30.         }   
    31.   
    32.         [DllImport("User32.dll")]   
    33.         public static extern bool GetCursorPos(ref POINT lpPoint);   
    34.   
    35.         [DllImport("User32.dll")]   
    36.         public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref RECT lpRect, uint fWinIni);   
    37.   
    38.         [DllImport("User32.dll")]   
    39.         public static extern bool GetWindowRect(IntPtr hwnd, ref RECT lpRect);   
    40.     }   
    41. }  
  • 相关阅读:
    linux下配置php的一些信息
    前端学习
    Verilog笔记.3.有限状态机
    Verilog笔记.2.数字逻辑电路
    Verilog笔记.1.基本语法
    python3爬虫.4.下载煎蛋网妹子图
    python3爬虫.3.下载网页图片
    python3爬虫.2.伪装浏览器
    python3爬虫.1.简单的网页爬虫
    python3学习笔记.3.条件控制与循环
  • 原文地址:https://www.cnblogs.com/qq260250932/p/4230484.html
Copyright © 2011-2022 走看看