靠边隐藏效果:当程序移动到显示的边界时,程序自动隐藏起来,留一条小边在外面,很酷的效果吧.
先介绍下实现原理,靠边隐藏无非就是判断窗体的位置和屏幕的四边的关系,当上左右三个方向超出的时候,就把窗体自动往上移,问题是...怎么判断窗体的位置呢?.Net里面有很方便的事件:LocationChanged,来判断窗体位置的变化,那又如何判断鼠标和窗体的关系呢?最简单的办法是用个 timer不停的去判断...,我最不想用这种方法实现,结果苦苦探寻了两个小时最终还是以这种最笨的方法来实现效果-_-#,如果不用timer,还有其他什么方法呢?我第一想到的是钩子,于是我拦截系统消息WM_MOVE,WM_MOVING,0x00a0................发现都无法满足要求,翻遍winnt.h也没发现有什么是进入窗体离开窗体时发出的消息,只有一个0x00a0是经过窗体边框时发的消息,不过呢如果鼠标移动太快,系统就收不到这个消息.... 此路不通,于是想看看.Net里面封装了什么事件, 很遗憾MouveEnter和MouseLeave会被上层的控件遮蔽,我总不能窗体上有多少控件都给设置Mouse事件吧.............,最后还是用timer来实现比较现实-_-#
我把它封装成一个.Net组件,这样以后的项目如果需要这种效果只需像引用Timer一样拖拽到窗体上,然后设置DockForm为需要效果的窗体就可以了
具体代码如下:
建一个自定义控件,然后记得建一个Timer,并设置Tick事件
using
System;
using
System.ComponentModel;
using
System.Diagnostics;
using
System.Text;
using
System.Windows.Forms;
using
System.Drawing;
namespace
QQClient.QQ.QQBuddy.Components
{
[Description(
"
窗体自动靠边隐藏组件 @Author: Red_angelX
"
)]
public
partial
class
AutoDockManage : Component
{
private
Form _form;
public
AutoDockManage()
{
InitializeComponent();
}
public
AutoDockManage(IContainer container)
{
container.Add(
this
);
InitializeComponent();
}
[Description(
"
用于控制要自动Dock的窗体
"
)]
public
Form DockForm
{
get
{
return
_form;
}
set
{
_form
=
value;
if
(_form
!=
null
)
{
_form.LocationChanged
+=
new
EventHandler(_form_LocationChanged);
_form.SizeChanged
+=
new
EventHandler(_form_SizeChanged);
_form.TopMost
=
true
;
}
}
}
private
bool
IsOrg
=
false
;
private
Rectangle lastBoard;
private
const
int
DOCKING
=
0
;
private
const
int
PRE_DOCKING
=
1
;
private
const
int
OFF
=
2
;
private
int
status
=
2
;
private
void
CheckPosTimer_Tick(
object
sender, EventArgs e)
{
if
(DesignMode)
{
return
;
}
if
(_form
==
null
||
IsOrg
==
false
)
{
return
;
}
if
(_form.Bounds.Contains(Cursor.Position))
{
/*
* 该死的.Net在移动时候不会发生该代码,必须在鼠标离开后才会执行
if (dockSide == AnchorStyles.None && status == OFF && IsOrg == true)
{
if (_form.Bounds.Width == lastBoard.Width && _form.Bounds.Height == lastBoard.Height)
{
return;
}
_form.Size = new Size(lastBoard.Width, lastBoard.Height);
return;
}
*/
switch
(dockSide)
{
case
AnchorStyles.Top:
if
(status
==
DOCKING)
_form.Location
=
new
Point(_form.Location.X,
0
);
break
;
case
AnchorStyles.Right:
if
(status
==
DOCKING)
_form.Location
=
new
Point(Screen.PrimaryScreen.Bounds.Width
-
_form.Width,
1
);
break
;
case
AnchorStyles.Left:
if
(status
==
DOCKING)
_form.Location
=
new
Point(
0
,
1
);
break
;
}
}
else
{
switch
(dockSide)
{
case
AnchorStyles.Top:
_form.Location
=
new
Point(_form.Location.X, (_form.Height
-
4
)
*
(
-
1
));
break
;
case
AnchorStyles.Right:
_form.Size
=
new
Size(_form.Width, Screen.PrimaryScreen.WorkingArea.Height);
_form.Location
=
new
Point(Screen.PrimaryScreen.Bounds.Width
-
4
,
1
);
break
;
case
AnchorStyles.Left:
_form.Size
=
new
Size(_form.Width, Screen.PrimaryScreen.WorkingArea.Height);
_form.Location
=
new
Point((
-
1
)
*
(_form.Width
-
4
),
1
);
break
;
case
AnchorStyles.None:
if
(IsOrg
==
true
&&
status
==
OFF)
{
if
(_form.Bounds.Width
!=
lastBoard.Width
||
_form.Bounds.Height
!=
lastBoard.Height)
{
_form.Size
=
new
Size(lastBoard.Width, lastBoard.Height);
}
}
break
;
}
}
}
internal
AnchorStyles dockSide
=
AnchorStyles.None;
private
void
GetDockSide()
{
if
(_form.Top
<=
0
)
{
dockSide
=
AnchorStyles.Top;
if
(_form.Bounds.Contains(Cursor.Position))
status
=
PRE_DOCKING;
else
status
=
DOCKING;
}
else
if
(_form.Left
<=
0
)
{
dockSide
=
AnchorStyles.Left;
if
(_form.Bounds.Contains(Cursor.Position))
status
=
PRE_DOCKING;
else
status
=
DOCKING;
}
else
if
(_form.Left
>=
Screen.PrimaryScreen.Bounds.Width
-
_form.Width)
{
dockSide
=
AnchorStyles.Right;
if
(_form.Bounds.Contains(Cursor.Position))
status
=
PRE_DOCKING;
else
status
=
DOCKING;
}
else
{
dockSide
=
AnchorStyles.None;
status
=
OFF;
}
}
private
void
_form_LocationChanged(
object
sender, EventArgs e)
{
GetDockSide();
if
(IsOrg
==
false
)
{
lastBoard
=
_form.Bounds;
IsOrg
=
true
;
}
}
private
void
_form_SizeChanged(
object
sender, EventArgs e)
{
if
(IsOrg
==
true
&&
status
==
OFF)
{
lastBoard
=
_form.Bounds;
}
}
}
}
转载请写上出处就行,代码可以随意改动,但要保持版权完整性,现在已知还有个小问题,
.Net机制中的窗体大小改变事件必须在鼠标离开窗体后才能执行,所以想要完美的隐藏效果,最好是自己画个标题栏
不过总体来说还算另我满意,VS 2005 编译没问题,2003似乎命名空间不能和类名相同?可能需要改少许代码