托盘显示许多软件都有这个功能,在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 }
详见工程 托盘显示演示