C#实现QQ靠边隐藏的功能

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. }

详细可以下载工程后自行研究