Нежелательное мерцание курсора при перемещении курсора внутри областей

#vb.net

Вопрос:

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

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

 Imports System.Drawing.Drawing2D

Public Class Form1
    Private myRectangles() As Rectangle
    Private myRegions(2) As Region

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Write an array of rectangles.
        myRectangles = {New Rectangle(100, 100, 50, 50), New Rectangle(200, 200, 50, 50), New Rectangle(300, 300, 50, 50)}

        ' Write an array of rectangle regions.
        For i As Integer = 0 To myRegions.length - 1
            Dim myPath As New GraphicsPath
            myPath.AddRectangle(myRectangles(i))

            Dim myRegion As New Region(myPath)
            myRegions(i) = myRegion
        Next
    End Sub

    Private Sub Form1_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
        ' Iterate myRegions to check if the mouse is over a region.
        For i As Integer = 0 To myRegions.Count - 1
            Dim IsHit As Boolean = myRegions(i).IsVisible(e.Location)

            If IsHit Then
                Cursor.Current = Cursors.Hand
                Exit For
            Else
                Cursor.Current = Cursors.Default
            End If
        Next
    End Sub

    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        ' Paint myRectangles.
        For i As Integer = 0 To myRegions.Length - 1
            e.Graphics.DrawRectangle(New Pen(Color.Black, 1), myRectangles(i))
        Next
    End Sub
End Class
 

EDIT1: Вышеприведенный подраздел MouseMove можно упростить до следующего:

 Private Sub Form1_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
    ' Check if the mouse is located within any region.
    Dim isHit As Boolean = myRegions.Any(Function(p) p.IsVisible(e.Location))

    If isHit Then
        Cursor.Current = Cursors.Hand
    Else
        Cursor.Current = Cursors.Default
    End If
End Sub
 

ПРАВКА2: Пересмотренный полный код:

 Imports System.Drawing.Drawing2D

Public Class Form1
    Private myRectangles() As Rectangle
    Private myGraphicsPaths As New List(Of GraphicsPath)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' Write a graphics path list of rectangles.
        myRectangles = {New Rectangle(100, 100, 50, 50), New Rectangle(200, 200, 50, 50), New Rectangle(300, 300, 50, 50)}

        For i As Integer = 0 To myRectangles.Length - 1
            Dim myPath As New GraphicsPath
            myPath.AddRectangle(myRectangles(i))
            myGraphicsPaths.Add(myPath)
        Next
    End Sub

    Private Sub Form1_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
        ' Check if the mouse is located within any graphicspath.
        Dim isHit As Boolean = myGraphicsPaths.Any(Function(p) p.IsVisible(e.Location))

        If isHit And Cursor.Current IsNot Cursors.Hand Then
            Cursor.Current = Cursors.Hand
        Else
            Cursor.Current = Cursors.Default
        End If
    End Sub

    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        ' Paint myRectangles.
        For i As Integer = 0 To myRectangles.Length - 1
            e.Graphics.DrawRectangle(New Pen(Color.Black, 1), myRectangles(i))
        Next
    End Sub
End Class
 

Комментарии:

1. Какая польза от этих регионов? Из того, что вы показываете здесь, похоже, что вы используете массив областей только для того, чтобы проверить, находится ли указатель мыши внутри одной из них. Вместо этого вы могли бы обработать a List(Of GraphicsPath) и использовать AddRectangle() для добавления ваших фигур в прямоугольнике. С помощью этого списка вы просто проверяете, есть ли dim isVisible = [YourListOfGraphicsPaths].Any(Function(p) p.IsVisble([Point])) . Если значение true, установите тип курсора — только если он еще не установлен — в противном случае измените его на другой.

2. Привет, Джими. Приведенный выше код является выдержкой из программы, которая будет анализировать ферменные мосты. Пользователь введет в datagridview координаты узлов фермы, т. е. местоположение, в котором пересекаются элементы фермы. Узлы фермы будут окрашены в виде кругов; со временем элементы фермы будут окрашены в виде прямоугольников. Я хочу, чтобы тип курсора мыши менялся на «рука», когда пользователь наводит курсор на узел/элемент, и чтобы был выбран соответствующий номер узла/элемента в представлении datagrid, а также для визуальной подсказки о возможности «выбрать» узел/элемент.

3. В любом случае, похоже, что ваше предложение, хотя и упрощает мой код, не решает проблему… если только Список(Из…) не делает чего-то, о чем я не знаю. См. выше упрощенный код для модуля MouseMove.

4. Ты упустил главное. У вас есть несколько фигур (прямоугольников), и это то, что вы используете для рисования. Это уже неправильно, так как вам нужно обрабатывать эти фигуры, а не просто рисовать их. Таким образом, как представляется, для управления этими фигурами вы вводите новую коллекцию областей, полученных из объекта GraphicsPath (от которого вы никогда не избавляетесь), просто чтобы использовать этот Isvisible() метод. Я предлагаю отказаться от коллекции областей и прямоугольников и просто использовать a List(Of GraphicsPath) для всех, чтобы упростить процедуру. — Тогда я также предложил установить курсор только в том случае, если он отличается от текущего, ни в коем случае.

5. Вы рисуете на поверхности Формы. Даже если предположить, что Форма имеет двойной буфер, я предлагаю не использовать ее поверхность для рисования. Используйте элемент управления с двойной буферизацией в качестве графического поля или плоской метки, оба из которых имеют двойную буферизацию самостоятельно. — В любом случае, не используйте области для определения того, содержится ли точка в фигуре. GraphicsPath предоставляет тот же метод, плюс IsOutlineVisible метод, аналогичный, но связанный только с границей пути. — Я сомневаюсь, что вам нужно всего 3 прямоугольника, явно больше, поэтому вычисления должны быть как можно быстрее.