Слушатель C# MouseEnter.NET на Управлении С Полосой прокрутки

Пока мышь по определенному управлению, мы показываем некоторую форму. Когда мышь выходит из-под контроля, мы скрываем управление после маленького тайм-аута. Это - стандартное поведение при наведении курсора.

Однако, когда управление (например, Treeview) имеет полосу прокрутки, и мышь работает или ПО полосе прокрутки, события не стреляют...

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

Как мы можем решить эту проблему?

8
задан Run CMD 9 June 2010 в 12:47
поделиться

2 ответа

Полоса прокрутки находится в неклиентской области представления дерева. Когда мышь перемещается туда, она начинает генерировать неклиентские сообщения типа WM_NCMOUSEMOVE и WM_NCMOUSELEAVE. Вам придется создать подкласс TreeView и переопределить WndProc(), чтобы обнаружить эти сообщения.

Однако это не решит вашу проблему, вам все равно будет трудно справиться с крайними случаями. Низкотехнологичный подход с таймером всегда работает:

    private Form frmPopup;

    private void treeView1_MouseEnter(object sender, EventArgs e) {
        timer1.Enabled = true;
        if (frmPopup == null) {
            frmPopup = new Form2();
            frmPopup.StartPosition = FormStartPosition.Manual;
            frmPopup.Location = PointToScreen(new Point(treeView1.Right + 20, treeView1.Top));
            frmPopup.FormClosed += (o, ea) => frmPopup = null;
            frmPopup.Show();
        }
    }

    private void timer1_Tick(object sender, EventArgs e) {
        Rectangle rc = treeView1.RectangleToScreen(new Rectangle(0, 0, treeView1.Width, treeView1.Height));
        if (!rc.Contains(Control.MousePosition)) {
            timer1.Enabled = false;
            if (frmPopup != null) frmPopup.Close();
        }
    }
3
ответ дан 5 December 2019 в 23:13
поделиться

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

Поместите элемент управления на панель, пристыкованную к заполнению, и используйте MouseEnter панели для включения вашего поведения - это будет включать полосу прокрутки элемента управления. Вы можете использовать и событие MouseLeave панели, но вам придется проверять положение курсора, чтобы убедиться, что он не переместился в содержащийся элемент управления. Этот метод в основном надежен, но быстрое перемещение мыши может сбить его с толку.

Если вы объедините этот метод с таймером, который запускается при отображении показанного/скрытого элемента управления и периодически проверяет положение курсора. Это будет работать, но ваш тайм-аут перед скрытием элемента управления не обязательно будет последовательным (потому что таймер запускается, когда они входят в элемент управления). Вы можете останавливать/запускать таймер при перемещении мыши в элементе управления, чтобы несколько облегчить эту проблему.

Я собрал проект различных методов, которые я пробовал здесь: http://lovethedot.s3.amazonaws.com/100609StackoverflowScrollbarQuestion.zip

Прикрепляя элемент управления, который вы хотите отслеживать, к панели, он по существу обертывает ее, и вы получите MouseEnter на самом краю отслеживаемого элемента управления:

    private void panel1_MouseEnter(object sender, EventArgs e)
    {
        this.Text = "in";
    }

    private void panel1_MouseLeave(object sender, EventArgs e)
    {
        if (!new Rectangle(new Point(0, 0), panel1.Size).Contains(panel1.PointToClient(Control.MousePosition)))
            this.Text = "out";
    }

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

Для лучшего восприятия "выхода" он совмещен с таймером, который также проверяет, где находится курсор:

        private void listBox3_MouseEnter(object sender, EventArgs e)
    {
        button1.Visible = true;
        visibleTimer.Stop();
        visibleTimer.Start();
    }

    void visibleTimer_Tick(object sender, EventArgs e)
    {
        if (!new Rectangle(new Point(0, 0), listBox3.Size).Contains(listBox3.PointToClient(Control.MousePosition)))
        {
            visibleTimer.Stop();
            button1.Visible = false;
        }
    }
2
ответ дан 5 December 2019 в 23:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: