c# 任务栏托盘图标鼠标进入MouseEnter和鼠标离开MouseLeave实现
c#的任务栏托盘图标控件NotifyIcon只有MouseMove事件,MouseMove事件刷新很快,很不好用,而且我们有时需要鼠标进入和离开的事件,但是不知道c#怎么回事,没有提供,那么就只能自己来处理了。
解决鼠标进入和离开的思路是:
1.通过MouseMove事件确定当前鼠标已经进入托盘图标的范围
2.进入后启动检测timer
3.定时检测托盘图标的位置和当前鼠标的位置,判断鼠标是否在托盘图标的范围内
主要难点:获取当前托盘图标的位置
获取托盘图标位置的思路:
1.查找到托盘图标所在的窗口
- private IntPtr FindTrayToolbarWindow()
- {
- IntPtr hWnd = FindWindow("Shell_TrayWnd", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "TrayNotifyWnd", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "SysPager", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);
- }
- }
- }
- return hWnd;
- }
2.遍历窗口内的托盘图标
3.获取当前托盘图标的句柄,通过句柄得到这个托盘图标所关联的进程id
4.通过进程id比较获取到当前程序的托盘图标
5.拖过api获取当前托盘图标相对于它所在窗口的位置
6.获取窗口在整个屏幕中的位置,在计算出托盘图标相对于屏幕的位置
2-6代码:
- private bool FindNotifyIcon(IntPtr hTrayWnd, ref Rect rectNotify)
- {
- UInt32 trayPid = ;
- Rect rectTray = new Rect();
- GetWindowRect(hTrayWnd, out rectTray);
- int count = (int) SendMessage(hTrayWnd, TB_BUTTONCOUNT, , IntPtr.Zero); //给托盘窗口发消息,得到托盘里图标
- bool isFind = false;
- if (count > )
- {
- GetWindowThreadProcessId(hTrayWnd, out trayPid); //取得托盘窗口对应的进程id
- //获取托盘图标的位置
- IntPtr hProcess = OpenProcess(ProcessAccess.VMOperation | ProcessAccess.VMRead | ProcessAccess.VMWrite,
- false, trayPid); //打开进程,取得进程句柄
- IntPtr address = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
- IntPtr.Zero,
- ,
- AllocationType.Commit,
- MemoryProtection.ReadWrite);
- TBBUTTON btnData = new TBBUTTON();
- TRAYDATA trayData = new TRAYDATA();
- // Console.WriteLine("Count:"+count);
- var handel = Process.GetCurrentProcess().Id;
- // Console.WriteLine("curHandel:" + handel);
- for (uint j = ; j < count; j++)
- {
- // Console.WriteLine("j:"+j);
- var i = j;
- SendMessage(hTrayWnd, TB_GETBUTTON, i, address); //取得TBBUTTON结构到本地
- int iTmp = ;
- var isTrue = ReadProcessMemory(hProcess,
- address,
- out btnData,
- Marshal.SizeOf(btnData),
- out iTmp);
- if (isTrue == false) continue;
- //这一步至关重要,不能省略
- //主要解决64位系统电脑运行的是x86的程序
- if (btnData.dwData == IntPtr.Zero)
- {
- btnData.dwData = btnData.iString;
- }
- ReadProcessMemory(hProcess, //从目标进程address处存放的是TBBUTTON
- btnData.dwData, //取dwData字段指向的TRAYDATA结构
- out trayData,
- Marshal.SizeOf(trayData),
- out iTmp);
- UInt32 dwProcessId = ;
- GetWindowThreadProcessId(trayData.hwnd, //通过TRAYDATA里的hwnd字段取得本图标的进程id
- out dwProcessId);
- //获取当前进程id
- // StringBuilder sb = new StringBuilder(256);
- // GetModuleFileNameEx(OpenProcess(ProcessAccess.AllAccess, false, dwProcessId), IntPtr.Zero, sb, 256);
- // Console.WriteLine(sb.ToString());
- if (dwProcessId == (UInt32) handel)
- {
- Rect rect = new Rect();
- IntPtr lngRect = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
- IntPtr.Zero,
- Marshal.SizeOf(typeof (Rect)),
- AllocationType.Commit,
- MemoryProtection.ReadWrite);
- i = j;
- SendMessage(hTrayWnd, TB_GETITEMRECT, i, lngRect);
- isTrue = ReadProcessMemory(hProcess, lngRect, out rect, Marshal.SizeOf(rect), out iTmp);
- //释放内存
- VirtualFreeEx(hProcess, lngRect, Marshal.SizeOf(rect), FreeType.Decommit);
- VirtualFreeEx(hProcess, lngRect, , FreeType.Release);
- int left = rectTray.Left + rect.Left;
- int top = rectTray.Top + rect.Top;
- int botton = rectTray.Top + rect.Bottom;
- int right = rectTray.Left + rect.Right;
- rectNotify = new Rect();
- rectNotify.Left = left;
- rectNotify.Right = right;
- rectNotify.Top = top;
- rectNotify.Bottom = botton;
- isFind = true;
- break;
- }
- }
- VirtualFreeEx(hProcess, address, 0x4096, FreeType.Decommit);
- VirtualFreeEx(hProcess, address, , FreeType.Release);
- CloseHandle(hProcess);
- }
- return isFind;
- }
7.如果没有找到,那么需要用相同的方法在托盘溢出区域内查找
- private IntPtr FindTrayToolbarOverFlowWindow()
- {
- IntPtr hWnd = FindWindow("NotifyIconOverflowWindow", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);
- }
- return hWnd;
- }
在查找中的难点:
1.对于32位操作系统和64位操作系统,系统内部处理方式不一样,所以许多时候当去取TBBUTTON结构到本地的时候得到的地址为0,这里查询了一些资料,网上一些资料TBBUTTON的结构体如下:
- [StructLayout(LayoutKind.Sequential, Pack = )]
- public struct TBBUTTON
- {
- public int iBitmap;
- public int idCommand;
- public byte fsState;
- public byte fsStyle;
- public byte bReserved0;
- public byte bReserved1;
- public IntPtr dwData;
- public IntPtr iString;
- }
这个在32位下面没有问题,但是在64位系统下就出现了问题,后面参考网上一些资料,原来问题出在中间4个byte中,由于32位系统中4个byte刚好32位,但是在64位中这里就不对,所以就修改为如下:
- [StructLayout(LayoutKind.Sequential, Pack = )]
- public struct TBBUTTON
- {
- public int iBitmap;
- public int idCommand;
- public IntPtr fsStateStylePadding;
- public IntPtr dwData;
- public IntPtr iString;
- }
修改过后在64位系统中运行通过了,在这样一位问题解决了,但是当我将解决方案迁移到程序当中的时候,却出了问题,一直不能得到地址,查找了很多原因,原来是在我程序编译的时候,生成的平台是X86,那么就造成了64位系统中使用32位平台时出现问题:
到这里我就猜想是不是 public IntPtr fsStateStylePadding;这一句出了问题,当时x86平台的时候,这个只占用了32位,但是实际64位系统这个位置应该要占用64位,造成地址不对,出错了。
那么接下来我就证实了下这个问题,在我获取地址的时候在public IntPtr dwData;字段中没有获取到,但是在public IntPtr iString;字段中获取到了,那么证明我的猜想是对的(真正是否正确还需要指正),
那么解决方案就来了,为了更好的兼容性,结构体不变,当获取dwData地址没有获取到的时候,我们查找iString字段就好了,方法在这里:
- //这一步至关重要,不能省略
- //主要解决64位系统电脑运行的是x86的程序
- if (btnData.dwData == IntPtr.Zero)
- {
- btnData.dwData = btnData.iString;
- }
把这个主要的解决了,后面就是查找当前托盘图标相对于父窗体的位置了,使用了很多方法:
GetWindowRect
ScreenToClient
GetClientRect
这些方法都没有成功,最后发现网上有这么一种方法。
- SendMessage(hTrayWnd, TB_GETITEMRECT, i, lngRect);
- isTrue = ReadProcessMemory(hProcess, lngRect, out rect, Marshal.SizeOf(rect), out iTmp);
在这里真正感受到c++的强大。
在解决这个问题的过程中,参考了很多方案,通过整合才解决了这个问题,如下:
http://blog.163.com/zjlovety@126/blog/static/22418624201142763542917/
http://blog.csdn.net/wzsy/article/details/47980317
http://www.cnblogs.com/hanf/archive/2011/08/09/2131641.html
等。
以下是调用方法:
- private void Load()
- {
- this._notifyIcon.MouseDoubleClick += notifyIcon_MouseDoubleClick;
- _notifyIcon.MouseMove += new MouseEventHandler(notifyIcon_MouseMove);
- CreateNotifyMouseHelper();
- }
- private NotifyIconMouseHelper notifyHelper;
- private Timer timer = null;
- private void CreateNotifyMouseHelper()
- {
- notifyHelper=new NotifyIconMouseHelper();
- notifyHelper.MouseEnterNotifyStatusChanged+= MouseEnterNotifyStatusChanged;
- }
- private void MouseEnterNotifyStatusChanged(object sender, bool isEnter)
- {
- if (isEnter)
- {
- Console.WriteLine("鼠标进入");
- }
- else
- {
- Console.WriteLine("鼠标离开");
- }
- }
以下是检测的源代码:
- using System;
- using System.Collections.Generic;
- using System.Data.Entity.Core.Metadata.Edm;
- using System.Diagnostics;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.Text;
- using System.Timers;
- using System.Windows;
- namespace NotifyTest
- {
- /*托盘图标鼠标进入离开事件
- */
- public delegate void MouseEnterNotifyStatusChangedHandel(object sender, bool isEnter);
- public class NotifyIconMouseHelper
- {
- #region win32类库
- [Flags()]
- public enum ProcessAccess : int
- {
- /// <summary>Specifies all possible access flags for the process object.</summary>
- AllAccess =
- CreateThread | DuplicateHandle | QueryInformation | SetInformation | Terminate | VMOperation | VMRead |
- VMWrite | Synchronize,
- /// <summary>Enables usage of the process handle in the CreateRemoteThread function to create a thread in the process.</summary>
- CreateThread = 0x2,
- /// <summary>Enables usage of the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.</summary>
- DuplicateHandle = 0x40,
- /// <summary>Enables usage of the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.</summary>
- QueryInformation = 0x400,
- /// <summary>Enables usage of the process handle in the SetPriorityClass function to set the priority class of the process.</summary>
- SetInformation = 0x200,
- /// <summary>Enables usage of the process handle in the TerminateProcess function to terminate the process.</summary>
- Terminate = 0x1,
- /// <summary>Enables usage of the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.</summary>
- VMOperation = 0x8,
- /// <summary>Enables usage of the process handle in the ReadProcessMemory function to' read from the virtual memory of the process.</summary>
- VMRead = 0x10,
- /// <summary>Enables usage of the process handle in the WriteProcessMemory function to write to the virtual memory of the process.</summary>
- VMWrite = 0x20,
- /// <summary>Enables usage of the process handle in any of the wait functions to wait for the process to terminate.</summary>
- Synchronize = 0x100000
- }
- [StructLayout(LayoutKind.Sequential)]
- private struct TRAYDATA
- {
- public IntPtr hwnd;
- public UInt32 uID;
- public UInt32 uCallbackMessage;
- public UInt32 bReserved0;
- public UInt32 bReserved1;
- public IntPtr hIcon;
- }
- [StructLayout(LayoutKind.Sequential, Pack = )]
- public struct TBBUTTON
- {
- public int iBitmap;
- public int idCommand;
- public IntPtr fsStateStylePadding;
- public IntPtr dwData;
- public IntPtr iString;
- }
- [Flags]
- public enum AllocationType
- {
- Commit = 0x1000,
- Reserve = 0x2000,
- Decommit = 0x4000,
- Release = 0x8000,
- Reset = 0x80000,
- Physical = 0x400000,
- TopDown = 0x100000,
- WriteWatch = 0x200000,
- LargePages = 0x20000000
- }
- [Flags]
- public enum MemoryProtection
- {
- Execute = 0x10,
- ExecuteRead = 0x20,
- ExecuteReadWrite = 0x40,
- ExecuteWriteCopy = 0x80,
- NoAccess = 0x01,
- ReadOnly = 0x02,
- ReadWrite = 0x04,
- WriteCopy = 0x08,
- GuardModifierflag = 0x100,
- NoCacheModifierflag = 0x200,
- WriteCombineModifierflag = 0x400
- }
- [DllImport("user32.dll", SetLastError = true)]
- private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
- [DllImport("user32.dll", SetLastError = true)]
- private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass,
- string lpszWindow);
- [DllImport("user32.dll", SetLastError = true)]
- private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
- [DllImport("kernel32.dll")]
- private static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess,
- [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- private static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg, UInt32 wParam, IntPtr lParam);
- [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
- private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
- int dwSize, AllocationType flAllocationType, MemoryProtection flProtect);
- [DllImport("kernel32.dll", SetLastError = true)]
- private static extern bool ReadProcessMemory(
- IntPtr hProcess,
- IntPtr lpBaseAddress,
- out TBBUTTON lpBuffer,
- int dwSize,
- out int lpNumberOfBytesRead
- );
- [DllImport("kernel32.dll", SetLastError = true)]
- private static extern bool ReadProcessMemory(
- IntPtr hProcess,
- IntPtr lpBaseAddress,
- out Rect lpBuffer,
- int dwSize,
- out int lpNumberOfBytesRead
- );
- [DllImport("kernel32.dll", SetLastError = true)]
- private static extern bool ReadProcessMemory(
- IntPtr hProcess,
- IntPtr lpBaseAddress,
- out TRAYDATA lpBuffer,
- int dwSize,
- out int lpNumberOfBytesRead
- );
- [DllImport("psapi.dll")]
- private static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName,
- [In] [MarshalAs(UnmanagedType.U4)] int nSize);
- [Flags]
- public enum FreeType
- {
- Decommit = 0x4000,
- Release = 0x8000,
- }
- [DllImport("kernel32.dll")]
- private static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, FreeType dwFreeType);
- [DllImport("kernel32.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool CloseHandle(IntPtr hObject);
- [StructLayout(LayoutKind.Sequential)]
- public struct POINT
- {
- public int X;
- public int Y;
- public POINT(int x, int y)
- {
- this.X = x;
- this.Y = y;
- }
- public override string ToString()
- {
- return ("X:" + X + ", Y:" + Y);
- }
- }
- [DllImport("user32")]
- public static extern bool GetClientRect(
- IntPtr hwnd,
- out Rect lpRect
- );
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
- public static extern bool GetCursorPos(out POINT pt);
- [StructLayout(LayoutKind.Sequential)]
- public struct Rect
- {
- public int Left;
- public int Top;
- public int Right;
- public int Bottom;
- }
- [DllImport("user32.dll")]
- private static extern int GetWindowRect(IntPtr hwnd, out Rect lpRect);
- public const int WM_USER = 0x0400;
- public const int TB_BUTTONCOUNT = WM_USER + ;
- public const int TB_GETBUTTON = WM_USER + ;
- public const int TB_GETBUTTONINFOW = WM_USER + ;
- public const int TB_GETITEMRECT = WM_USER + ;
- #endregion
- #region 检测托盘图标相对于屏幕位置
- private bool FindNotifyIcon(ref Rect rect)
- {
- Rect rectNotify = new Rect();
- IntPtr hTrayWnd = FindTrayToolbarWindow(); //找到托盘窗口句柄
- var isTrue = FindNotifyIcon(hTrayWnd, ref rectNotify);
- if (isTrue == false)
- {
- hTrayWnd = FindTrayToolbarOverFlowWindow(); //找到托盘窗口句柄
- isTrue = FindNotifyIcon(hTrayWnd, ref rectNotify);
- }
- rect = rectNotify;
- return isTrue;
- }
- private IntPtr FindTrayToolbarWindow()
- {
- IntPtr hWnd = FindWindow("Shell_TrayWnd", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "TrayNotifyWnd", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "SysPager", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);
- }
- }
- }
- return hWnd;
- }
- private IntPtr FindTrayToolbarOverFlowWindow()
- {
- IntPtr hWnd = FindWindow("NotifyIconOverflowWindow", null);
- if (hWnd != IntPtr.Zero)
- {
- hWnd = FindWindowEx(hWnd, IntPtr.Zero, "ToolbarWindow32", null);
- }
- return hWnd;
- }
- private bool FindNotifyIcon(IntPtr hTrayWnd, ref Rect rectNotify)
- {
- UInt32 trayPid = ;
- Rect rectTray = new Rect();
- GetWindowRect(hTrayWnd, out rectTray);
- int count = (int) SendMessage(hTrayWnd, TB_BUTTONCOUNT, , IntPtr.Zero); //给托盘窗口发消息,得到托盘里图标
- bool isFind = false;
- if (count > )
- {
- GetWindowThreadProcessId(hTrayWnd, out trayPid); //取得托盘窗口对应的进程id
- //获取托盘图标的位置
- IntPtr hProcess = OpenProcess(ProcessAccess.VMOperation | ProcessAccess.VMRead | ProcessAccess.VMWrite,
- false, trayPid); //打开进程,取得进程句柄
- IntPtr address = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
- IntPtr.Zero,
- ,
- AllocationType.Commit,
- MemoryProtection.ReadWrite);
- TBBUTTON btnData = new TBBUTTON();
- TRAYDATA trayData = new TRAYDATA();
- // Console.WriteLine("Count:"+count);
- var handel = Process.GetCurrentProcess().Id;
- // Console.WriteLine("curHandel:" + handel);
- for (uint j = ; j < count; j++)
- {
- // Console.WriteLine("j:"+j);
- var i = j;
- SendMessage(hTrayWnd, TB_GETBUTTON, i, address); //取得TBBUTTON结构到本地
- int iTmp = ;
- var isTrue = ReadProcessMemory(hProcess,
- address,
- out btnData,
- Marshal.SizeOf(btnData),
- out iTmp);
- if (isTrue == false) continue;
- //这一步至关重要,不能省略
- //主要解决64位系统电脑运行的是x86的程序
- if (btnData.dwData == IntPtr.Zero)
- {
- btnData.dwData = btnData.iString;
- }
- ReadProcessMemory(hProcess, //从目标进程address处存放的是TBBUTTON
- btnData.dwData, //取dwData字段指向的TRAYDATA结构
- out trayData,
- Marshal.SizeOf(trayData),
- out iTmp);
- UInt32 dwProcessId = ;
- GetWindowThreadProcessId(trayData.hwnd, //通过TRAYDATA里的hwnd字段取得本图标的进程id
- out dwProcessId);
- //获取当前进程id
- // StringBuilder sb = new StringBuilder(256);
- // GetModuleFileNameEx(OpenProcess(ProcessAccess.AllAccess, false, dwProcessId), IntPtr.Zero, sb, 256);
- // Console.WriteLine(sb.ToString());
- if (dwProcessId == (UInt32) handel)
- {
- Rect rect = new Rect();
- IntPtr lngRect = VirtualAllocEx(hProcess, //在目标进程中申请一块内存,放TBBUTTON信息
- IntPtr.Zero,
- Marshal.SizeOf(typeof (Rect)),
- AllocationType.Commit,
- MemoryProtection.ReadWrite);
- i = j;
- SendMessage(hTrayWnd, TB_GETITEMRECT, i, lngRect);
- isTrue = ReadProcessMemory(hProcess, lngRect, out rect, Marshal.SizeOf(rect), out iTmp);
- //释放内存
- VirtualFreeEx(hProcess, lngRect, Marshal.SizeOf(rect), FreeType.Decommit);
- VirtualFreeEx(hProcess, lngRect, , FreeType.Release);
- int left = rectTray.Left + rect.Left;
- int top = rectTray.Top + rect.Top;
- int botton = rectTray.Top + rect.Bottom;
- int right = rectTray.Left + rect.Right;
- rectNotify = new Rect();
- rectNotify.Left = left;
- rectNotify.Right = right;
- rectNotify.Top = top;
- rectNotify.Bottom = botton;
- isFind = true;
- break;
- }
- }
- VirtualFreeEx(hProcess, address, 0x4096, FreeType.Decommit);
- VirtualFreeEx(hProcess, address, , FreeType.Release);
- CloseHandle(hProcess);
- }
- return isFind;
- }
- #endregion
- public MouseEnterNotifyStatusChangedHandel MouseEnterNotifyStatusChanged;
- private object moveObject = new object();
- private bool isOver = false;
- private Timer timer = null;
- public void MouseEnter()
- {
- lock (moveObject)
- {
- if (isOver) return;
- //加载鼠标进入事件
- MouseEnter(true);
- CreateCheckTimer();
- timer.Enabled = true;
- }
- }
- private void CreateCheckTimer()
- {
- if (timer != null) return;
- timer = new Timer();
- timer.Interval = ;
- timer.Elapsed += TimerOnElapsed;
- }
- private void TimerOnElapsed(object sender, ElapsedEventArgs arg)
- {
- //300毫秒检测一次
- //判断鼠标是否在托盘图标内
- //如果在,那么就不管
- //如果不在,就加载鼠标离开事件,同时停止timer
- var isEnter = CheckMouseIsEnter();
- if (isEnter) return;
- timer.Enabled = false;
- MouseEnter(false);
- }
- private void MouseEnter(bool isEnter)
- {
- isOver = isEnter;
- if (MouseEnterNotifyStatusChanged == null) return;
- MouseEnterNotifyStatusChanged(this, isEnter);
- }
- public Point Point { get; set; }
- private bool CheckMouseIsEnter()
- {
- //这里怎么检测呢
- //我很无语啊
- //第一步:获取当前鼠标的坐标
- //第二步:获取托盘图标的坐标
- // ???? 难难难难难难难难难难
- try
- {
- Rect rectNotify = new Rect();
- var isTrue = FindNotifyIcon(ref rectNotify);
- if (isTrue == false) return false;
- POINT point = new POINT();
- GetCursorPos(out point);
- // Console.WriteLine(string.Format(@"
- //Left={0} Top={1} Right={2} Bottom={3}", rectNotify.Left, rectNotify.Top, rectNotify.Right, rectNotify.Bottom));
- // Console.WriteLine(point.X + " " + point.Y);
- //第三步:比较鼠标图标是否在托盘图标的范围内
- if (point.X >= rectNotify.Left && point.X <= rectNotify.Right &&
- point.Y >= rectNotify.Top && point.Y <= rectNotify.Bottom)
- {
- Point = new Point(point.X, point.Y);
- return true;
- }
- else
- {
- return false;
- }
- }
- catch (Exception)
- {
- return false;
- }
- }
- }
- }
c# 任务栏托盘图标鼠标进入MouseEnter和鼠标离开MouseLeave实现的更多相关文章
- mouseover与mouseenter,mouseout与mouseleave的区别
mouseover事件:不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件,对应mouseout事件: mouseenter事件:只有在鼠标指针穿过被选元素时,才会触发 mouse ...
- Adobe Edge Animate –获取鼠标位置及跟随鼠标功能实现
Adobe Edge Animate –获取鼠标位置及跟随鼠标功能实现 版权声明: 本文版权属于 北京联友天下科技发展有限公司. 转载的时候请注明版权和原文地址. 在网络上浏览有关Edge相关问题的时 ...
- win7旗舰版任务栏窗口不合并显示,鼠标移至窗口时可预览应用内容
1.鼠标移至任务栏--右键--属性: 2.选择"当任务栏被占满时合并"或"从不合并",第一个选项更优: 3.右键桌面"计算机"的" ...
- mouseover和mouseenter,mouseout和mouseleave的区别-引发的探索
相信小伙伴们都用过鼠标事件,比如mouseover和mouseout,mouseenter和mouseleave.它们都分别表示鼠标移入移出. 在使用的过程中,其实一直有个小疑问——它们之间究竟有什么 ...
- mouseover,mouseenter,mouseout,mouseleave的区别
mouseover :不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件. mouseout :不论鼠标指针离开被选元素还是任何子元素,都会触发 mouseout 事件. mous ...
- html body标签的几个属性 禁用鼠标右键,禁用鼠标选中文字等
<body oncontextmenu='return false' ondragstart='return false' onselectstart ='return false' onsel ...
- OpenCV鼠标画图例程,鼠标绘制矩形
鼠标画矩形: // An example program in which the // user can draw boxes on the screen. // /* License: Oct. ...
- 【.Net】鼠标点击控制鼠标活动范围 ClipCursor
可以使用API ClipCursor,如果你不嫌麻烦的话. 以下方法: Private Sub Form1_MouseDown(sender As System.Object, e As System ...
- 2017年10月21日 CSS常用样式&鼠标样式 以及 jQuery鼠标事件& jQuery图片轮播& jQuery图片自动轮播代码
css代码 背景与前景 background-color:#0000; //背景色,样式表优先级高 background-image:url(路径); //设置背景图片 background-atta ...
随机推荐
- sqlite与sqlserver区别
1.查询时把两个字段拼接在一起 --sqlserver-- select Filed1+'@'+Filed2 from table --sqlite-- select Filed1||'@'||Fil ...
- js为Object对象动态添加属性和值 eval c.k c[k]
const appendInfo = () => { const API_SECRET_KEY = 'https://github.com/dyq086/wepy-mall/tree/maste ...
- pgsql 数据类型
- 洛谷3243 [HNOI2015]菜肴制作
题目戳这里 Solution 错误的想法:正向建图,然后从入度为0的点选出最小u的开始输出,然后找出u连接的点v,并把v的度数减一,再次把入度为0的点加入小根堆,这样显然有错,因为只能局部保证最小,后 ...
- Django项目之【学员管理系统】
Django项目[学员管理系统] 项目规划阶段 项目背景 现实生活中,特别是在学校,传统的excel统计管理学员信息的方式已经无法满足日渐增长的业务需求. 因此需一套方便易用的“学员管理系统”,来提高 ...
- Android数据格式化
1.文件大小格式化: Log.d(TAG, Formatter.formatFileSize(this, 100)); //100 B Log.d(TAG, Formatter.formatFileS ...
- datetime-local设置初始值
//全局变量 var format = ""; //构造符合datetime-local格式的当前日期 function getFormat(){ format = "& ...
- Maximum Subsequence Sum 【DP】
Given a sequence of K integers { N1, N2, -, NK }. A continuous subsequence is defined to be ...
- Django 后台管理 之登录和注销
Session: session是服务器端生成保存的一个键值对 , session内部机制依赖于cookie . 用户登录后返回给客户端一个随机字符串,客户端带着随机字符串访问服务器,用于验证 ...
- blog真正的首页
声明:此Django分类下的教程是追梦人物所有,地址http://www.jianshu.com/u/f0c09f959299,本人写在此只是为了巩固复习使用 上一节我们阐明了django的开发流程, ...