您的位置:首页 > 编程语言 > C#

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

2015-01-17 15:13 741 查看
http://www.cnblogs.com/yechensi/archive/2009/08/02/1537145.html

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

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

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

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

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

FormDockTemplate.cs文件:

view plaincopy to clipboardprint?

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

}

}

view plaincopy to clipboardprint?

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;

}

}

}

}

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

view plaincopy to clipboardprint?

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);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: