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 ...
随机推荐
- 10个迷惑新手的Cocoa&Objective-c开发问题
本文转载至 http://blog.csdn.net/lvxiangan/article/details/27964733 language background runtime thre ...
- 之前博客中的代码都放到github上
之前一直把代码托管在taocode上,现在已经不能用了,所以把代码整理了一下,统一都放在gibhub上了. LALR(1)语法分析生成器:https://github.com/kiven-li/xby ...
- input file 选择Excel文件 相关操作
1.HTML代码 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebFo ...
- 在tomcat下直接访问Html报错,说找不到资源(404)
今天由于工作需要,想把一个html直接放到tomcat(干净的tomcat,没有做过任何修改.)下进行访问,然后根据经验就直接在webapps下创建了个文件夹test,然后把需要的test.html拷 ...
- OSGI简介(转)
原文地址 目前,业内关于OSGI技术的学习资源或者技术文档还是很少的.我在某宝网搜索了一下“OSGI”的书籍,结果倒是有,但是种类少的可怜,而且几乎没有人购买.因为工作的原因我需要学习OSGI,所以我 ...
- SPDIF接口细则详解
链接:https://max.book118.com/html/2017/0422/101658483.shtm
- CMake最好的学习资料
本文为转载,阅读不友好,请先查看原文:https://blog.gmem.cc/cmake-study-note 收下为原文内容================> 基础知识 CMake简介 CM ...
- g2o的一般过程
1.自己定义顶点类.边类或者用已经有的.1.1定义顶点例子class CurveFittingVertex: public g2o::BaseVertex<3, Eigen::Vector3d& ...
- POJ2104 K-th Number —— 静态区间第k小
题目链接:http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Sub ...
- linux 下监控进程流量情况命令 NetHogs
摘自: http://www.cnblogs.com/kerrycode/p/4748970.html NetHogs介绍 NetHogs是一款开源.免费的,终端下的网络流量监控工具,它可监控Linu ...