【问题标题】:How to handle click event on shapes of System.Drawing如何处理 System.Drawing 形状上的点击事件
【发布时间】:2017-03-19 11:48:51
【问题描述】:

我一直在尝试在 winforms vb.net 应用程序中达到以下结果

Desired Result

此图像中的每个弧或圆都是可点击的, 可点击的弧线是粉红色的。

我设法编写了以下代码

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

    'Create pen objects 
    Dim p As New Pen(Color.Green, 30)
    Dim p1 As New Pen(Color.Yellow, 30)
    Dim p2 As New Pen(Color.Red, 30)
    Dim p3 As New Pen(Color.Blue, 30)

    'Create rectangle objects 
    Dim rt As New Rectangle(160, 150, 80, 100)
    Dim rt1 As New Rectangle(100, 150, 80, 100)
    Dim rt2 As New Rectangle(130, 120, 80, 100)
    Dim rt3 As New Rectangle(130, 180, 80, 100)

    'Draw arcs 
    e.Graphics.DrawArc(p, rt, 45, -90)
    e.Graphics.DrawArc(p1, rt1, -135, -90)
    e.Graphics.DrawArc(p2, rt2, -45, -90)
    e.Graphics.DrawArc(p3, rt3, 135, -90)

End Sub

导致以下输出。

Output

我没想到的是:

1- 如何为每个弧线制作边框。

2- 如何处理每个弧上的点击。

有没有比我试图解决这个问题更好的方法。

任何帮助将不胜感激。

【问题讨论】:

  • 不,您不能将 Rectangle.Contains 用于 Arcs。你应该使用GraphicsPath.IsVisible。看看这个帖子,例如:How can I treat the circle as a control after drawing it?。另请查看这篇文章以绘制这些弧线。 How to draw a circular progressbar pie using GraphicsPath in WinForm?
  • 您可以简单地创建一个类,其中包含绘制和命中测试对象所需的信息、一个Rectangle 属性以及StartAngleEndAngle 的两个整数属性。然后您可以简单地执行命中测试和绘图。对于绘图,接受Graphics 对象作为Draw 方法的参数并在其上绘制路径。
  • 仅在需要时才会引发绘制事件。当表单需要重新绘制时,例如当您从最小化中恢复它时,或者当您将另一个窗口移到它上面时。你不需要做任何事情。只需设置DoubleBuffered = true 即可进行无闪烁绘画。
  • 事实上,您不需要对此评论进行投票,请转到问题页面并单击问题附近和答案附近的向上箭头 :) this onethis one
  • 我可以将它作为第一个帖子的副本关闭。您也可以根据链接的帖子发布自己的答案。你喜欢什么?

标签: .net vb.net winforms visual-studio .net-4.0


【解决方案1】:

特别感谢 Reza Aghaei 的帮助, 我在我的解决方案中使用了以下代码

编辑:改进的答案

配置图形路径,让代码更整洁

Imports System.Drawing.Drawing2D
Public Class SurfaceSelection

Private Sub SurfaceSelection_Click(sender As Object, e As MouseEventArgs) Handles Me.Click
    Dim hitSurface As String = String.Empty
    If GetPath(EnumsClass.SurfacesEnum.L).IsVisible(e.Location) Then
        hitSurface = "L"
    ElseIf GetPath(EnumsClass.SurfacesEnum.M).IsVisible(e.Location) Then
        hitSurface = "M"
    ElseIf GetPath(EnumsClass.SurfacesEnum.F).IsVisible(e.Location) Then
        hitSurface = "F"
    ElseIf GetPath(EnumsClass.SurfacesEnum.D).IsVisible(e.Location) Then
        hitSurface = "D"
    Else
        hitSurface = "Missed"
    End If

    MsgBox(hitSurface)

End Sub

Private Sub SurfaceSelection_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

    Me.DrawPath(EnumsClass.SurfacesEnum.L, e)
    Me.DrawPath(EnumsClass.SurfacesEnum.M, e)
    Me.DrawPath(EnumsClass.SurfacesEnum.F, e)
    Me.DrawPath(EnumsClass.SurfacesEnum.D, e)

End Sub

Private Sub DrawPath(ByVal v_bytSurface As EnumsClass.SurfacesEnum, ByVal e As System.Windows.Forms.PaintEventArgs)
    Using p As GraphicsPath = GetPath(v_bytSurface)
        e.Graphics.FillPath(Brushes.Green, p)
        e.Graphics.DrawPath(Pens.Black, p)
    End Using
End Sub

Private Function GetPath(ByVal v_bytSurface As EnumsClass.SurfacesEnum) As GraphicsPath
    Dim path As New GraphicsPath
    Dim center = New Point(100, 100)
    Dim innerR = 70
    Dim thickness = 20
    Dim startAngle = getGraphicsPathAngle(v_bytSurface)
    Dim arcLength = 70
    Dim outerR = innerR + thickness
    Dim outerRect = New Rectangle(center.X - outerR, center.Y - outerR, 2 * outerR, 2 * outerR)
    Dim innerRect = New Rectangle(center.X - innerR, center.Y - innerR, 2 * innerR, 2 * innerR)
    path.AddArc(outerRect, startAngle, arcLength)
    path.AddArc(innerRect, startAngle + arcLength, -arcLength)
    path.CloseFigure()
    Return path
End Function

Private Function getGraphicsPathAngle(ByVal v_bytSurface As EnumsClass.SurfacesEnum) As Integer
    Select Case v_bytSurface
        Case EnumsClass.SurfacesEnum.F
            Return 235
        Case EnumsClass.SurfacesEnum.O
            Return 0
        Case EnumsClass.SurfacesEnum.L
            Return 55
        Case EnumsClass.SurfacesEnum.M
            Return 145
        Case EnumsClass.SurfacesEnum.D
            Return 325
        Case EnumsClass.SurfacesEnum.Unspecified
            Return -1

    End Select

End Function

End Class

Public Class EnumsClass
    Public Enum SurfacesEnum As Byte
        Unspecified = 0
        F = 1
        O = 2
        L = 3
        M = 4
        D = 5
    End Enum
End Class

我在以下 stackoverflow 问题中使用了 Reza 的答案:

How to draw a circular progressbar pie using GraphicsPath in WinForm?

How can I treat the circle as a control after drawing it? - Moving and selecting shapes

How to drag and move shapes in C#

【讨论】:

  • 顺便说一句,答案有内存泄漏你正在一遍又一遍地在绘画事件中创建一些GraphicsPath
  • 您应该只创建一次。如果您一遍又一遍地创建它们而不释放它们,您将收到一些异常,甚至会在创建窗口句柄时遇到一些问题。你应该解决这个问题!
  • 是的,你可以清除它,但是GDI资源应该被释放,清除不等于释放。例如,您可以不将它们存储在表单级别,而是将主题放在方法中的 using 块中。
  • 考虑this example 中的Circle 类或this example 中的HitTest 方法
  • 干得好!现在好了:)
猜你喜欢
  • 1970-01-01
  • 2019-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多