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 ...
随机推荐
- Linux 命令汇总总结相关
玩了linux快一年,简单总结下网络相关的命令,具体每个命令的参数可以用到再细看. 1.ifconfig:查询.设置网卡和IP网段等相关参数,包括MTU.2.ifup.ifdown:这两个命令就是一个 ...
- ES mapping映射及优化
mapping映射 主要类型: 同一index下,不同type中如果有相同filed:es进行mapping映射的时候,按照先写进去的指定类型:比如同一index,包含的type中都有key1字段,如 ...
- iOS 跳转到Appstore的链接及二维码
1.应用内部跳转到Appstore 1.跳转到应用详情 [[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"it ...
- An Overview of Query Optimization in Relational Systems
An Overview of Query Optimization in Relational Systems
- 我的Android进阶之旅------>Android使用AlarmManager全局定时器实现定时更换壁纸
该DEMO将会通过AlarmManager来周期的调用ChangeService,从而让系统实现定时更换壁纸的功能. 更换壁纸的API为android.app.WallpaperManager,它提供 ...
- python cookbook第三版学习笔记六:迭代器与生成器
假如我们有一个列表 items=[1,2,3].我们要遍历这个列表我们会用下面的方式 For i in items: Print i 首先介绍几个概念:容器,可迭代对象,迭代器 容器是一种存储数据 ...
- python3用pdfminer3k在线读取pdf文件
import importlib import sys import random from urllib.request import urlopen from urllib.request imp ...
- web 全栈 学习 1 工程师成长思路图
第一部分: 技术的三个阶段 实现 ---> 借鉴 ---> 优化 实现:为了实现功能,不考虑可读性.借鉴:阅读开源代码,开源程序,学到编程思想.优化:可读性,可执行. 阶段一:实现多做事, ...
- 原生Base64编码/解码(OC与Swift)
Objective-C NSString *plainString = @"foo"; Encoding NSData *plainData = [plainString data ...
- javah生成带有包名的头文件
无包名情况 多数的demo都是基于这种条件,假设在目录jni/下有一个包含native方法的文件Hello.class.进入jni/目录,直接执行javah Hello,就可以在jni/目录下生成文件 ...