我的贴子“怎么知道鼠标在控件上面刚停下?”里问了一个问题,可是觉得大家的处理不太理想,我好好查了一下Control的用法,终于得到了一个较好的处理方法。原贴地址:
http://community.csdn.net/Expert/topic/5193/5193513.xml?temp=.569195我的处理是这样的:
重写控件的MouseHover及MouseMove两个基类的方法,如下:protected override void OnMouseHover(EventArgs e)
{
System.Console.WriteLine(DateTime.Now);
base.OnMouseHover(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
base.ResetMouseEventArgs();
}
注释:
把上面的代码放入到自己的代码里(如果是窗体里则直接放,如果继承的控件,就放到控件的代码里)编译程序及运行后,大家就会看到每当鼠标停下来的时候都会引发一次MouseHover事件而会在输出窗口里输出当前时间的字符串,真在太高兴了。
因为这也是个技术问题,只不过自己解决了,特来感谢原贴参与者并放分一次。
------------
好希望能把这个加入FAQ!

解决方案 »

  1.   

    等我研究一下ResetMouseEventArgs()
      

  2.   

    我看了一下源码,这个方法最终调用的本地方法_TrackMouseEvent但是它的flag设置为dwFlags = 3
    也就是说dwFlags = TME_HOVER + TME_LEAVE
    应该是把悬停和离开的事件都重置了,我的建议是自己调用_TrackMouseEvent方法只重置TME_HOVER,稍后给出源码。
      

  3.   

    虽然可以实现,但闪得历害,不是我想要的效果我在 OnMouseHover 中显示 ToolTip,鼠标放在那不动,几乎每秒闪了两次。另外不明白要在 OnMouseHover 中加入 System.Console.WriteLine(DateTime.Now); 这句话是什么意思,应该无意义吧
      

  4.   

    贴出源码
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;namespace WindowsApplication1
    {
        public partial class Form1 : Form
        {
            bool flag = false;
            public Form1()
            {
                InitializeComponent();
            }        private bool MyTrackMouseEvent(IntPtr handle)
            {
                TRACKMOUSEEVENT tme = new TRACKMOUSEEVENT();
                tme.dwFlags = 1;  //注意这里,这里只重置了TME_HOVER
                tme.hwndTrack = handle;
                return _TrackMouseEvent(tme);
            }
            [DllImport("comctl32.dll", ExactSpelling = true)]
            private static extern bool _TrackMouseEvent(TRACKMOUSEEVENT tme);        private void button1_MouseMove(object sender, MouseEventArgs e)
            {
                if (flag)
                {
                    MyTrackMouseEvent((sender as Control).Handle);
                    flag = !flag;
                }
            }        private void button1_MouseHover(object sender, EventArgs e)
            {
                textBox1.AppendText(DateTime.Now.ToString()+"\n");
                flag = true;
            }
        }
        [StructLayout(LayoutKind.Sequential)]
        public class TRACKMOUSEEVENT
        {
            public int cbSize;
            public int dwFlags;
            public IntPtr hwndTrack;
            public int dwHoverTime;
            public TRACKMOUSEEVENT() {
                this.cbSize = Marshal.SizeOf(typeof(TRACKMOUSEEVENT));
                this.dwHoverTime = 400;
            }
        }
    }
      

  5.   

    TO raozhiven(朗屹) ( ) 信誉:99    Blog 你的会“几乎每秒闪了两次”吗?
    其它有人试也是这样吗?
    怎么我这里不是?TO flyforlove(为情飞) ( ) 信誉:100    Blog 
    不想调用API来做。
      

  6.   

    你重寫的是MouseHover事件觸發后的處理方法,可是在控件里面移動停止并不觸發MouseHover事件,你重寫的方法當然也是不能調用的!
      

  7.   

    TO GXY2005(晓晨美眉好^_^) ( ) 信誉:91    Blog 
    不明白你的意思,
    我不是已经调用到了吗?
      

  8.   

    你在Winform里面,比如textbox里面使用你重寫的是MouseHover事件,在textbox內部移動停止一樣不觸發你重寫的MouseHover事件
      

  9.   

    在 MouseMove 中调用了 ResetMouseEventArgs,那么,鼠标在控件上即使不移动,我想也会再次引 MouseMove。再次引发 MouseMove 的事件时,必然再次引发 MouseHover 事件、再次 ResetMouseEventArgs 。一个恶性循环。
      

  10.   

    TO raozhiven(朗屹) ( ) 信誉:99    Blog 鼠标不动也会用MouseMove事件?
      

  11.   

    to hbxtlhx(平民百姓) 因为调用了 ResetMouseEventArgs,猜测是这样,等我试试
      

  12.   

    raozhiven(朗屹) ( ) 信誉:99    Blog  2006-11-30 15:28:10  得分: 0  
     
     
       to hbxtlhx(平民百姓) 因为调用了 ResetMouseEventArgs,猜测是这样,等我试试
      
     
    ---------不会的,你看了源代码就知道了它只发送windows不能发送的wm_buttonhover和wm_buttonleave
      

  13.   

    一个笨办法:
    加一个Timer,间隔设在你想要的时间(就是鼠标停在控件上多久引发“停下”事件)
    在 MouseMove 事件里 Enable 这个 Timer,同时保存当前鼠标的XY坐标
    在 Timer_Tick 事件里检查当前鼠标的XY坐标是否与保存下来的一样,如果一样则说明鼠标停止移动了,这时 Disable 这个 Timer 同时手动触发你想要的事件(可以自己写一个或者直接调用你想调用的代码)
      

  14.   

    其實症結在無法得到鼠标停止事件!
    我個人認為
    1.要么在move事件中預測鼠标在停止前很短時間運行趨勢,也就是判斷坐標變化趨勢來判斷是否要停止了。不是狠准確,前一帖偶說過了。
    2.使用timer等,在mousemove也不觸發時也能比較坐標,從而判斷出鼠标停止了。
    3.要么改寫鼠标事件觸發機制。不知道怎么作
      

  15.   

    怪事出现了protected override void OnMouseMove(MouseEventArgs e)
    {
      try
      {
        ......
      }
      finally
      {
        base.OnMouseMove(e);
        base.ResetMouseEventArgs();
      }
    }protected override void OnMouseHover(EventArgs e)
    {
       base.OnMouseHover(e);  //将断点设在此,居然没反应
    }
      

  16.   

    将 base.ResetMouseEventArgs(); 注释掉又可以了,奇怪
      

  17.   

    晕,收藏此贴出错,请版主出来看看什么原因:
    Server Error in '/' Application.
    --------------------------------------------------------------------------------Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation. 
    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.ArgumentException: Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.Source Error: An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  Stack Trace: 
    [ArgumentException: Invalid postback or callback argument.  Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%@ Page EnableEventValidation="true" %> in a page.  For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them.  If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.]
       System.Web.UI.ClientScriptManager.ValidateEvent(String uniqueId, String argument) +2082537
       System.Web.UI.Control.ValidateEvent(String uniqueID, String eventArgument) +106
       System.Web.UI.WebControls.TextBox.LoadPostData(String postDataKey, NameValueCollection postCollection) +31
       System.Web.UI.WebControls.TextBox.System.Web.UI.IPostBackDataHandler.LoadPostData(String postDataKey, NameValueCollection postCollection) +11
       System.Web.UI.Page.ProcessPostData(NameValueCollection postData, Boolean fBeforeLoad) +408
       System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3776 
    --------------------------------------------------------------------------------
    Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.210
      

  18.   

    GXY2005(晓晨美眉好^_^) -------------------------关于这个帖子,你发言很多,但是根本就不知道你再说什么,感觉你还没搞清楚wm_mousehover是怎么回事。我解释一下吧,mousehover事件严格来说不是windows事件,而是一个自定义事件,因为它不是windows默认发出的,需要用TrackMouseEvent来注册。另外,mousehover事件并不是鼠标停止以后发生的,它有个事件和范围,也就是说在给定的一段时间内只要鼠标的地移动范围没有超出给出的范围就可以了,系统默认给定时间是400,移动范围是4x4 dot的范围。
    所以可以看出为什么进入控件后,只触发一次这样的事件。
    假设说可以多次触发的话,那么触发一次后,下一次从什么时候开始计算?比如说鼠标一直在4X4的范围内运动,那么是不是超过400毫秒后,一直都要触发这个事件呢?所以严格来按照mousehover的定义,必须在每次触发mousehover事件后,再次寻找开始点。严格来说,楼主给出的代码有缺陷,
    一个是,只要鼠标运动,就会重新注册时间(也就是说发送TrackMouseEvent)
    再就是,只要鼠标不停,即时是在给定的范围内运动,都不会触发mousehover事件,这个不符合定义。
    我上面给的一个例子,用了一个flag变量,就是为了寻找下一次的开始点,我用的是触发一次mousehover后,再开始计算。
      

  19.   

    sorry,上面的几个地方,由于输入问题,时间和事件都混了。另外,mousehover事件并不是鼠标停止以后发生的,它有个事件和范围,
    改为
    另外,mousehover事件并不是鼠标停止以后发生的,它有个时间和范围,
    一个是,只要鼠标运动,就会重新注册时间(也就是说发送TrackMouseEvent)
    改为
    一个是,只要鼠标运动,就会重新注册事件(也就是说发送TrackMouseEvent)
      

  20.   

    flyforlove(为情飞) ( ) 信誉:100    Blog 
    -------------------
    你使用API根本不在我們討論范圍!
      

  21.   

    GXY2005(晓晨美眉好^_^) ------------------------你错了,如果你这样说的话,就是没有通过现象看本质,楼主所使用的方法,最终调用的就是那个API,即时在外面包装多少层,都无法改变它的本质。
      

  22.   

    是的,最終還是調用API
    不過我是上層軟件編程,能不用API就不用.
    偵測滑鼠Leave及Hover事件
    C++ void Class::OnMouseMove(UINT nFlags, CPoint point)
    {
      TRACKMOUSEEVENT trackmouseevent;
      trackmouseevent.cbSize = sizeof(trackmouseevent);
      trackmouseevent.dwFlags = TME_HOVER | TME_LEAVE;
      trackmouseevent.hwndTrack = GetSafeHwnd();
      trackmouseevent.dwHoverTime = 0x00000001;
      _TrackMouseEvent(&trackmouseevent);
     
      Class::OnMouseMove(nFlags, point);

      

  23.   

    其实我也没有说一定要用API,我只是想用API来说明到底wm_mousehover是怎么回事。知道是怎么回事了,那么具体用什么方法,那就看个人喜好了。
      

  24.   

    hbxtlhx(平民百姓) ( ) 信誉:112    Blog  2006-11-30 15:31:49  得分: 0   
       
    我在北京,税前9K
    -------------------------------
    佩服樓主,象你學習!
    多半是主管了!經理之類吧,純粹程序員恐怕拿不了!
      
     
      

  25.   

    呵呵 ,base.ResetMouseEventArgs();这个东西起作用了?
      

  26.   

    思想精彩.原来
    private void dataGrid1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
    {
    Thread.Sleep(500);//这句是废话,跟断点加的
    base.ResetMouseEventArgs();
    }//这样就成,谢楼长 终于明白怎么重置这家伙了;
      

  27.   

    感觉把base.ResetMouseEventArgs();放在MouseMove里触发的次数多了,放到MouseHover事件更合适.这样就不用管鼠标移动事件了.如下:protected override void OnMouseHover(EventArgs e)
    {
        base.OnMouseHover(e);
        this.ResetMouseEventArgs();
    }这个效果更好.
      

  28.   

    我上面的程序不是已经考虑这种情况了么,就是因为用API实现的,没有人仔细看么,这儿用C#的人,都是在哪块转过来的?还是一上来就直接学C#的?
      

  29.   

    利用Ontimer事件,读鼠标的位置,如果n次是同一个位置,就说明鼠标停止不动.
      

  30.   

    非常感谢,我copy一份去试一下,如果ok,以后会用的到
      

  31.   

    我觉得还是使用Hover事件比较好吧 
    不知道是不是LZ想要的效果呢
      

  32.   

    再次引发 MouseMove 的事件时,必然再次引发 MouseHover 事件、再次 ResetMouseEventArgs 。一个恶性循环。