托盘显示许多软件都有这个功能,在C#中如何实现呢,下面的方法可以实现托盘显示,不过可能有些复杂。
首先,需要在工具栏拖入NotifyIcon,如图1的那个控件。
图一:
然后,设置NotifyIcon的属性,加图标什么的。
最后,最主要的,就是NotifyIcon点击事件,要实现点击托盘图标隐藏窗口,再点击显示窗口,还有右键托盘能显示菜单等。
下面着重介绍一下这一部分的实现。
一、点击托盘右键菜单
这个NotifyIcon本身就有这个属性,即NotifyIcon.ContextMenu,添加相应菜单即可。
详见托盘显示演示的 AddTrayMenuItem()方法。
二、隐藏至托盘和显示
该部分使用user32.dll中的函数,如下:
1、bool SetWindowPos( IntPtr hWnd, IntPtr hWndAfter, int x, int y, int cx, int cy, uint flags)
函数功能:
该函数改变一个子窗口,弹出式窗口式顶层窗口的尺寸,位置和Z序。 子窗口,弹出式窗口,及顶层窗口根据它们在屏幕上出现的顺序排序、顶层窗口设置的级别最高,并且被设置为Z序的第一个窗口。
2、IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildAfter,string lpszClass,string lpszWindow)
函数功能:
该函数获得一个窗口的句柄,该窗口的类名和窗口名与给定的字符串相匹配。这个函数查找子窗口,从排在给定的子窗口后面的下一个子窗口开始。在查找时不区分大小写。
3、int GetWindowRect(IntPtr hwnd, ref RECT lpRect)
函数功能:
该函数返回指定窗口的边框矩形的尺寸。该尺寸以相对于屏幕坐标左上角的屏幕坐标给出。
4、DrawAnimatedRects( IntPtr hwnd, int ani, ref RECT from,ref RECT to)
函数功能:
在窗口缩放时产生动画效果
部分代码如下:
ChangeTrayStateManager类:
public class ChangeTrayStateManager
{
public static void Animate( IntPtr handle, Rectangle fromRect, Rectangle toRect)
{
try
{
TrayStateMethods.RECT from = TrayStateMethods.RECT.FromRectangle(fromRect);
TrayStateMethods.RECT to = TrayStateMethods.RECT.FromRectangle(toRect);
TrayStateMethods.DrawAnimatedRects(
handle,
TrayStateMethods.IDANI_CAPTION,
ref from,
ref to);
}
catch
{ }
}
public static void Animate( Form animateForm, Control owner)
{
Animate(animateForm.Handle, animateForm.Bounds, owner.RectangleToScreen(owner.ClientRectangle));
}
public static void Animate( Form animateForm,Rectangle bounds,bool minimized)
{
try
{
if (minimized)
{
Animate( animateForm.Handle, GetNotificationRect(), animateForm.Bounds);
}
else
{
Animate(animateForm.Handle, animateForm.Bounds, GetNotificationRect());
}
}
catch
{ }
}
private static Rectangle GetNotificationRect()
{
TrayStateMethods.RECT rect = new TrayStateMethods.RECT();
IntPtr hwnd = TrayStateMethods.FindWindowEx( IntPtr.Zero, IntPtr.Zero,"Shell_TrayWnd", null);
if (hwnd == IntPtr.Zero)
{
throw new Win32Exception();
}
hwnd = TrayStateMethods.FindWindowEx(hwnd, IntPtr.Zero,"TrayNotifyWnd", null);
if (hwnd == IntPtr.Zero)
{
throw new Win32Exception();
}
hwnd = TrayStateMethods.FindWindowEx( hwnd, IntPtr.Zero, "SysPager", null);
if (hwnd == IntPtr.Zero)
{
throw new Win32Exception();
}
hwnd = TrayStateMethods.FindWindowEx( hwnd,IntPtr.Zero,"ToolbarWindow32", null);
if (hwnd == IntPtr.Zero)
{
throw new Win32Exception();
}
TrayStateMethods.GetWindowRect(hwnd, ref rect);
return rect.Rect;
}
}
TrayStateMethods类,引用user32.dll方法。
public class TrayStateMethods
{
public const int IDANI_CAPTION = 0x3;
public const int WM_SYSCOMMAND = 0x0112;
public const uint SWP_NOZORDER = 0x0004;
public const uint SWP_NOREDRAW = 0x0008;
public const int HWND_TOPMOST = -1;
public const int SW_HIDE = 0x0;
public const int SW_NORMAL = 0x1;
public const int SW_RESTORE = 9;
public const int SW_MAXIMIZE = 3;
public enum SystemCommands
{
SC_SIZE = 0xF000,
SC_MOVE = 0xF010,
SC_MINIMIZE = 0xF020,
SC_MAXIMIZE = 0xF030,
SC_MAXIMIZE2 = 0xF032,
SC_NEXTWINDOW = 0xF040,
SC_PREVWINDOW = 0xF050,
SC_CLOSE = 0xF060,
SC_VSCROLL = 0xF070,
SC_HSCROLL = 0xF080,
SC_MOUSEMENU = 0xF090,
SC_KEYMENU = 0xF100,
SC_ARRANGE = 0xF110,
SC_RESTORE = 0xF120,
SC_RESTORE2 = 0xF122,
SC_TASKLIST = 0xF130,
SC_SCREENSAVE = 0xF140,
SC_HOTKEY = 0xF150,
SC_DEFAULT = 0xF160,
SC_MONITORPOWER = 0xF170,
SC_CONTEXTHELP = 0xF180,
SC_SEPARATOR = 0xF00F
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public RECT(int left, int top, int right, int bottom)
{
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
public Rectangle Rect
{
get
{
return new Rectangle(
this.Left, this.Top, this.Right - this.Left, this.Bottom - this.Top);
}
}
public static RECT FromXYWH(int x, int y, int width, int height)
{
return new RECT(x,
y,
x + width,
y + height);
}
public static RECT FromRectangle(Rectangle rect)
{
return new RECT(rect.Left,
rect.Top,
rect.Right,
rect.Bottom);
}
}
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(
IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
[DllImport("user32.dll")]
public static extern int GetWindowRect(IntPtr hwnd, ref RECT lpRect);
[DllImport("user32.dll")]
public static extern bool DrawAnimatedRects(
IntPtr hwnd,
int ani,
ref RECT from,
ref RECT to);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(
IntPtr hWnd,
IntPtr hWndAfter,
int x,
int y,
int cx,
int cy,
uint flags);
}
主界面调用:
public partial class Form1 : Form
{
private bool isInTray = false;
private Rectangle rectBounds;
public Form1()
{
InitializeComponent();
new Thread(new ThreadStart(AddTrayMenuItem)).Start();
}
#region Event
private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (isInTray)
{
ShowForm();
}
else
{
MiniToTray();
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Normal;
}
void hideItem_Click(object sender, EventArgs e)
{
MiniToTray();
}
void showItem_Click(object sender, EventArgs e)
{
ShowForm();
}
void exitItem_Click(object sender, EventArgs e)
{
this.Close();
}
#endregion
#region Method
private void AddTrayMenuItem()
{
ContextMenu cm = new ContextMenu();
MenuItem showItem = new MenuItem("显示主界面");
showItem.Click += new EventHandler(showItem_Click);
MenuItem miSeparator0 = new MenuItem("-");
miSeparator0.Enabled = false;
MenuItem hideItem = new MenuItem("最小化到托盘");
hideItem.Click += new EventHandler(hideItem_Click);
MenuItem miSeparator1 = new MenuItem("-");
miSeparator1.Enabled = false;
MenuItem exitItem = new MenuItem("退出");
exitItem.Click += new EventHandler(exitItem_Click);
cm.MenuItems.AddRange(new MenuItem[] { showItem, miSeparator0, hideItem, miSeparator1, exitItem });
this.notifyIcon1.ContextMenu = cm;
this.notifyIcon1.ContextMenu.MenuItems[0].Visible = false;
this.notifyIcon1.ContextMenu.MenuItems[1].Visible = false;
}
private void MiniToTray()
{
ChangeTrayStateManager.Animate(this, Bounds, false);
rectBounds = Bounds;
Hide();
isInTray = true;
this.notifyIcon1.ContextMenu.MenuItems[0].Visible = true;
this.notifyIcon1.ContextMenu.MenuItems[1].Visible = true;
this.notifyIcon1.ContextMenu.MenuItems[2].Visible = false;
this.notifyIcon1.ContextMenu.MenuItems[3].Visible = false;
}
private void ShowForm()
{
if (isInTray)
{
TrayStateMethods.SetWindowPos(
Handle,
new IntPtr(-1),
rectBounds.X,
rectBounds.Y,
rectBounds.Width,
rectBounds.Height,
TrayStateMethods.SWP_NOREDRAW | TrayStateMethods.SWP_NOZORDER);
ChangeTrayStateManager.Animate(this, rectBounds, true);
this.Show();
this.Activate();
isInTray = false;
this.notifyIcon1.ContextMenu.MenuItems[0].Visible = false;
this.notifyIcon1.ContextMenu.MenuItems[1].Visible = false;
this.notifyIcon1.ContextMenu.MenuItems[2].Visible = true;
this.notifyIcon1.ContextMenu.MenuItems[3].Visible = true;
if (this.WindowState == FormWindowState.Minimized)
{
this.WindowState = FormWindowState.Normal;
}
}
}
#endregion
}
详见工程 托盘显示演示