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

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 文件:

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

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文件:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Runtime.InteropServices;
  6. namespace DockWindow
  7. {
  8. class User32
  9. {
  10. [StructLayout(LayoutKind.Sequential)]
  11. public struct POINT
  12. {
  13. public int X;
  14. public int Y;
  15. }
  16. [StructLayout(LayoutKind.Sequential)]
  17. public struct RECT
  18. {
  19. public int left;
  20. public int top;
  21. public int right;
  22. public int bottom;
  23. }
  24. public enum Enu_SystemParametersInfo_Action
  25. {
  26. SPI_GETWORKAREA = 0x0030
  27. }
  28. [DllImport("User32.dll")]
  29. public static extern bool GetCursorPos(ref POINT lpPoint);
  30. [DllImport("User32.dll")]
  31. public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref RECT lpRect, uint fWinIni);
  32. [DllImport("User32.dll")]
  33. public static extern bool GetWindowRect(IntPtr hwnd, ref RECT lpRect);
  34. }
  35. }

C#如何实现类似QQ那样靠边隐藏的功能的更多相关文章

  1. 实现类似QQ自拍头像的功能(demo源码)

    在很多软件系统中,都允许用户设置自己的头像,甚至可以直接使用摄像头照相作为自己的头像,就像QQ的自拍头像功能一样. 这种功能是如何实现的了?最直接的,我们可以使用Windows提供的VFW技术或Dir ...

  2. QQ揭秘:如何实现窗体靠边隐藏?【低调赠送:QQ高仿版GG 4.2 最新源码】

    QQ有个靠边隐藏的功能,使用起来很方便:在屏幕上拖动QQ的主窗体,当窗体的上边沿与屏幕的上边沿对齐时,主窗体就会duang~~地隐藏起来,当将鼠标移到屏幕上边沿的对应区域时,主窗体又会duang~~显 ...

  3. WinForm实现类似QQ停靠,显示隐藏过程添加特效效果

    原文:WinForm实现类似QQ停靠,显示隐藏过程添加特效效果 这可能是个老题长谈的问题了,只是在项目中会用到这个效果,所以今天做个记录.大家见了别喷我.在项目中的需求是这样的. 打开程序,在屏幕的右 ...

  4. winform-实现类似QQ停靠桌面上边缘隐藏的效果

    //实现类似QQ停靠桌面上边缘隐藏的效果! private void timer1_Tick(object sender, EventArgs e) { System.Drawing.Point pp ...

  5. 使用plupload做一个类似qq邮箱附件上传的效果

    公司项目中使用的框架是springmvc+hibernate+spring,目前需要做一个类似qq邮箱附件上传的功能,暂时只是上传小类型的附件 处理过程和解决方案都需要添加附件,处理过程和解决方案都可 ...

  6. 用C#代码实现类似QQ窗体的“上、左、右”停靠功能

    大家都知道QQ有一个自动停靠功能,即“上.左.右”,当你把窗体拖到屏幕边缘,然后移开鼠标它会自动缩放,然后只显示一小小点出来,我们仔细观察会发现其实它只露3像素左右的边缘,当你鼠标移上去它又会伸出来, ...

  7. iOS tableViewCell 在cell赋值、网络加载照片位置偏移大小错乱,做一个类似qq列表的tableview 更新3

    更新3: 问题 加载慢!(一时间给的处理负载过大,要分散)在下载图片,判断状态后 对每个cell对图片灰置图片处理保存,影响了主线程的操作 :上拉加载时,无法上下滑动tableview 无法点击cel ...

  8. 【WPF】实现类似QQ聊天消息的界面

    最近公司有个项目,是要求实现类似 QQ 聊天这种功能的. 如下图 这没啥难的,稍微复杂的也就表情的解析而已. 表情在传输过程中的实现参考了新浪微博,采用半角中括号代表表情的方式.例如:“abc[dog ...

  9. C#利用API制作类似QQ一样的右下角弹出窗体

    C#利用API制作类似QQ一样的右下角弹出窗体 (2009-03-21 15:02:49) 转载▼ 标签: 杂谈 分类: .NET using System;using System.Collecti ...

随机推荐

  1. topcoder srm 698 div1 -3

    1.定义重复串$S=T+T$,即$S$可以表示成一个串的叠加.给定一个串$s$,可以通过删除字符.修改字符.增加字符来使得其变为重复串.问最少的次数. 思路:首先将$s$分成个串$s_{0},s_{1 ...

  2. 再谈 tp的 实例化 类 的自动加载

    表示一个域名下的所有/任何主机 使用 的格式是: [*.] example.com 其中 , example.com叫着 裸域名. (这个example.com/net/org不能被注册, 被保留) ...

  3. CF 1087解题报告

    cf解题报告 记录一下吧 做出:T1 rating :-97 想起几个月前做不出T1还是有点小搞笑呀2333 T1 双指针+特判 T2 发现k特别小,枚举剩余系 还要判断是否是能被n整除 移项发现可以 ...

  4. Python中的open和codecs.open

    最近老被编码困扰,多次折腾之后,感觉python的编解码做得挺好的,只要了解下边的流程,一般都能解决 input文件(gbk, utf-8...) ----decode-----> unicod ...

  5. Winform选择目录路径与选择文件路径

    https://blog.csdn.net/zaocha321/article/details/52528279 using System.Collections.Generic; using Sys ...

  6. 到底什么是 ROI Pooling Layer ???

    到底什么是 ROI Pooling Layer ??? 只知道 faster rcnn 中有 ROI pooling, 而且其他很多算法也都有用这个layer 来做一些事情,如:SINT,检测的文章等 ...

  7. Unity3D学习笔记(三十二):Xlua(2)

    Xlua支持通过子类对象访问父类的变量属性和方法   对于C#的ref,out参数的方法 当调用的时候:out类型的参数是不需要传递实参的,普通的参数和ref参数需要传递实参. out,ref传出值通 ...

  8. Images之管理image

    Manage images The easiest way to make your images available for use by others inside or outside your ...

  9. 传输SO10 (SO10 Transport)

    传输SO10 (SO10 Transport) 方法一.   手工添加到请求里面,格式为: R3TR TEXT text object, name, ID, language   方法二.使用程序:R ...

  10. forEach、map、filter、find、sort、some等易错点整理

    一.常用方法解析   说起数组操作,我们肯定第一反应就是想到forEach().map().filter()等方法,下面分别阐述一下各方法的优劣. 1.forEach 1.1 基础点   forEac ...