Make a window that pops up from taskbar
使用过 MSN Messager 的朋友都知道 , 当有好友连接到 Internet 的时候 , 在 taskbar( 任务栏 ) 的右上方 , 也就是整个屏幕的右下方会缓缓升起一个提示窗口。
其实 , 要使用 C# 来实现这种效果并不难。整个思想就是不断地改变窗口的位置 , 在 C# 中 , 就是设置 Form 的 Location 属性。下面我们来实现它吧 J
Step 1): 制作窗口
要完成设计 , 一个窗体自然是不可或缺的。新建一个 Windows Application, 将窗体的 FormBorderStyle 属性设置为 None,ShowInTaskbar 属性设置为 False. 并做适当的界面布置 ( 比如设置 BackgroundImage 什么的 ).
至此 , 窗体制作完毕。
Step 2): 为窗体添加 LostFocus 事件处理
由于在 Step 1) 中的设置 , 这个窗口不能被关闭掉 ( 当然 , 你可以在窗体上布局一些控件 , 进而实现窗体的关闭 , 这里不采用此方法 ), 你得在窗体失去焦点的时候将其关闭。 LostFocus 事件可以帮助你实现这一点。具体实现如下 :
// 注册事件
this .LostFocus += new EventHandler(MyDialog_LostFocus);
// 处理
private void MyDialog_LostFocus( object sender, EventArgs e)
{
this .Close(); // 关闭窗体即可
}
Step 3) 实现动画效果
要实现我们的目标 , 表面上看来似乎很容易。其实不然 , 一个难缠的问题是如何获取 taskbar 的位置及其高度。我们知道 ,taskbar 可能会位于屏幕四周的某一个位置上 , 同时 taskbar 的高度可以动态调整。
这里 , 我采用的解决办法是使用 Win32 API, 其中使用 FindWindow 函数来获得 taskbar 的句柄 (handle), 并通过 GetWindowRect 函数来获取其窗口矩形。通过这两个函数的配合使用 , 实现了动画效果。
首先添加一个类 NativeAPI, 用来声明要使用到的 API, 如下 :
public class NativeAPI
{
[DllImport("user32.dll", EntryPoint="FindWindow")]
public static extern IntPtr FindWindow (
string lpClassName,
string lpWindowName
);
[DllImport("user32.dll", EntryPoint="GetWindowRect")]
public static extern bool GetWindowRect (
IntPtr hwnd,
out Rectangle lpRect
);
}
当然 , 为了能够通过编译 , 你要添加上 :
using System;
using System.Runtime.InteropServices;
using System.Drawing;
我们知道 ,taskbar 的类名为 "Shell_TrayWnd", 从而调用 FindWindow 函数获取其窗口句柄不是什么难事。有了这个句柄 , 调用 GetWindowRect 获取其窗口矩形也不成问题 , 一旦获得了这个窗口矩形 , 根据窗口矩形的位置便可以判断出 taskbar 所处的位置了。似乎一切都很明了了 , 不过这里有个小问题你得注意 .C# 定义的 Rectangle 实例是使用顶点坐标 , 宽度和高度表达的 , 而从 API 返回的 Rectangle 实例 ( 本来不是该结构实例 , 而是 RECT 结构 , 这里偷懒 , 省去该结构的定义 J ) 是采用两个点的方式来定义的 , 即是 (Left,Top) 和 (Right,Bottom) 两点。因此 , 在使用返回的 Rectangle 结构实例的时候 , 要小心这点。下面是实现的代码 :
private Rectangle taskbarBound;// 包围 taskbar 的矩形
//……
private void ShowIt(){
// 获取 taskbar 的窗口句柄
IntPtr handle = NativeAPI.FindWindow("Shell_TrayWnd", null );
if (handle == IntPtr.Zero) return ; // 获取失败 ,return
// 获取屏幕分辨率
Size screenSize = SystemInformation.PrimaryMonitorSize;
// 获取 taskbar 的窗口矩形
if (NativeAPI.GetWindowRect(handle, out taskbarBound)){
// 获取成功
if (taskbarBound.X == 0 && taskbarBound.Y == 0){
if (taskbarBound.Width == screenSize.Width)
ShowItWhenTaskbarTop();//taskbar 在上面
else
ShowItWhenTaskbarLeft();//taskbar 在左边
}
else {
if (taskbarBound.X == 0)
ShowItWhenTaskbarBottom();//taskbar 在下面
else
ShowItWhenTaskbarRight();//taskbar 在右边
}
}
}
// 若 taskbar 在上面
private void ShowItWhenTaskbarTop(){
// 设置窗体的初始位置为右上方 , 并隐藏在 taskbar 内
this .Location = new Point(taskbarBound.Width - this .Width,taskbarBound.Height - this .Height);
// 向下运动
while ( this .Location.Y < taskbarBound.Height)
this .Location = new Point( this .Location.X, this .Location.Y + 1);
}
// 若 taskbar 在左边
private void ShowItWhenTaskbarLeft(){
// 设置窗体的初始位置为左下方 , 并全部在屏幕外
this .Location = new Point(taskbarBound.Width,taskbarBound.Height);
// 向上移出
while ( this .Location.Y > taskbarBound.Height - this .Height)
this .Location = new Point( this .Location.X, this .Location.Y - 1);
}
// 若 taskbar 在右边
private void ShowItWhenTaskbarRight(){
// 设置窗体的初始位置为右下方 <SPAN lang=EN-US style="FONT-SIZE: 10pt; F