Несколько событий MouseHover в элементе управления - PullRequest
7 голосов
/ 01 мая 2009

Я пытаюсь реализовать пользовательский элемент управления в C #, и мне нужно получать события, когда мышь наведена. Я знаю, что есть событие MouseHover, но оно срабатывает только один раз. Чтобы снова запустить его, мне нужно взять мышку и снова ввести его.

Есть ли способ, которым я могу это сделать?

Ответы [ 5 ]

8 голосов
/ 01 мая 2009

Давайте определим «прекращение движения» как «остается в радиусе x пикселей в течение n мс».

Подпишитесь на событие MouseMove и используйте таймер (установленный на n мс), чтобы установить время ожидания. Каждый раз, когда мышь двигается, проверяйте соответствие допустимым отклонениям. Если это за пределами вашего допуска, сбросьте таймер и запишите новое происхождение.

псевдокод:

Point lastPoint;
const float tolerance = 5.0;

//you might want to replace this with event subscribe/unsubscribe instead
bool listening = false;

void OnMouseOver()
{
    lastpoint = Mouse.Location;
    timer.Start();
    listening = true; //listen to MouseMove events
}

void OnMouseLeave()
{
    timer.Stop();
    listening = false; //stop listening
}

void OnMouseMove()
{
    if(listening)
    {
        if(Math.abs(Mouse.Location - lastPoint) > tolerance)
        {
            //mouse moved beyond tolerance - reset timer
            timer.Reset();
            lastPoint = Mouse.Location;
        }
    }
}

void timer_Tick(object sender, EventArgs e)
{
    //mouse "stopped moving"
}
6 голосов
/ 23 октября 2009

Я понимаю, что это старая тема, но я хотел бы поделиться способом, которым я нашел, чтобы сделать это: для вызова события перемещения мыши вызовите ResetMouseEventArgs () для элемента управления, который перехватывает событие.

2 голосов
/ 01 мая 2009

Почему бы не подписаться на события MouseMove в событии MouseHover, а затем отписаться в событии MouseLeave

Edit:

Один из способов определить, остановлена ​​ли мышь, состоит в том, чтобы запускать таймер каждый раз, когда вы получаете событие перемещения мыши, по истечении этого времени вы можете считать, что мышь остановлена. Причина удаления событий MouseMove в MouseLeave позволит вам получать события, только когда мышь находится под вашим контролем.

1 голос
/ 18 августа 2012

Это была самая чистая реализация, которую я мог придумать. Работает довольно хорошо:

    [DllImport("user32.dll")]
    static extern IntPtr SendMessage
    (
        IntPtr controlHandle,
        uint message,
        IntPtr param1,
        IntPtr param2
    );

    const uint WM_MOUSELEAVE = 0x02A3;

    Point lastMousePoint = Point.Empty;

    void richTextBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (Math.Abs(e.Location.X - lastMousePoint.X) > 1 || Math.Abs(e.Location.Y - lastMousePoint.Y) > 1)
        {
            lastMousePoint = e.Location;

            SendMessage((sender as RichTextBox).Handle, WM_MOUSELEAVE, IntPtr.Zero, IntPtr.Zero);
        }
    }

    void richTextBox_MouseHover(object sender, EventArgs e)
    {
        foo();
    }
0 голосов
/ 10 марта 2016

Вот немного более простая версия, которая не использует таймер. Просто запишите время последнего движения мыши, а затем сравните текущее время всякий раз, когда вы хотите проверить, зависает ли мышь.

    private DateTime mouseMoveTime = DateTime.Now;
    private Point mouseMoveLoc = new Point();

    private bool IsHovering()
    {
        return (mouseMoveTime.AddMilliseconds(SystemInformation.MouseHoverTime)).CompareTo(DateTime.Now) < 0;
    }

    private void myControl_MouseMove(object sender, MouseEventArgs e)
    {
        // update mouse position and time of last move
        if (Math.Abs(e.X - mouseMoveLoc.X) > SystemInformation.MouseHoverSize.Width || 
            Math.Abs(e.Y - mouseMoveLoc.Y) > SystemInformation.MouseHoverSize.Height)
        {
            mouseMoveLoc = new Point(e.X, e.Y);
            mouseMoveTime = DateTime.Now;
        }
    }

Или действительно короткая версия, не имеющая допуска на расстояние.

    private DateTime mouseMoveTime = DateTime.Now;

    private bool IsHovering()
    {
        return (mouseMoveTime.AddMilliseconds(SystemInformation.MouseHoverTime)).CompareTo(DateTime.Now) < 0;
    }

    private void myControl_MouseMove(object sender, MouseEventArgs e)
    {
        mouseMoveTime = DateTime.Now;
    }

Просто используйте if (IsHovering ()) ... когда вам нужно проверить, движется ли мышь.

Одна вещь, которую я заметил, это то, что MouseMove не срабатывает при перетаскивании. Однако вы можете скопировать код обновления mouseMoveTime / Loc в событие перетаскивания, чтобы обойти это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...