Make a window that pops up from taskbar

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

Published At
Categories with Web编程
Tagged with
comments powered by Disqus