应用程序冻结,但不会崩溃? (VISUAL BASIC)

时间:2019-11-04 12:36:23

标签: vb.net charts freeze

因此,我一直在为一个学校项目工作,其中一部分必须计算弹丸运动的坐标,然后将其添加到一系列点图上并绘制在应用程序上。唯一的问题是,如果速度太高(这将增加飞行和范围飞行的总时间,导致坐标的设置更大),则应用程序冻结-但不会崩溃。它没有显示任何错误,就像我使用Visual Studio 2013一样。

我将为该过程附加代码,有人可以发现为什么冻结和/或如何修复它?

我只是一个初学者,所以对编程知识不多,对您的帮助将不胜感激。

For x As Integer = 0 To totalTime Step 0.01
    Dim xPos As Double = findXLocation(velocity, angle, x)
    Dim yPos As Double = findYLocation(velocity, angle, x, elevation, totalTime, heightOfProjectile, flightRange)

    Chart1.Series("Projection").Points.AddXY(xPos, yPos)

    Dim label As New CalloutAnnotation

    With label
        Chart1.Annotations.Add(label)
    End With
Next 

我发现加快计算速度的一种方法是将步长(最初为0.01)减小到更高的水平,这意味着将减少计算量。但这将导致大量的If语句,因为case语句还会导致这些点的计算冻结。我还尝试设置一个变量,称为“增量”,将其设置为步长值。可以用许多不同的方法进行计算-我最初尝试过increment = totalTime / 1000,但这再次导致了应用程序完全冻结,尽管输入了什么速度。

findYLocation和findXLocation也可能有用,并附在下面。

Public Function findYLocation(ByVal velocity As Double, ByVal angle As Double, ByVal time As Double, ByVal elevation As Double, ByVal totalTime As Double, ByVal heightOfProjectile As Double, ByVal flightRange As Double) As Double
    Dim y As Double

    y = -(0.5 * gConstant * sq(time)) + (findVerticalVelocity(velocity, angle) * time) + elevation
    ' y = Math.Round(y, 1)

    If y < 0 Then
        y = 0
    End If

    Return y
End Function

Public Function findXLocation(ByVal velocity As Double, ByVal angle As Double, ByVal time As Double) As Double
    Dim x As Double

    x = findHorizontalVelocity(velocity, angle) * time
    ' x = Math.Round(x, 1)

    If x < 0 Then
        x = 0
    End If

    Return x
End Function

2 个答案:

答案 0 :(得分:1)

您可以尝试暂停程序,并检查导致该程序冻结的操作(在Visual Studio中,左侧为“停止”按钮旁边的按钮)。 Pause button on the left

您还可以尝试在代码中添加一些日志记录,以查看问题的根源所在。

Console.WriteLine("Logging")

甚至可以安排计算时间(有关更多信息,请参见https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.stopwatch?view=netframework-4.8

答案 1 :(得分:1)

问题出在这一行

For x As Integer = 0 To totalTime Step 0.01

x是一个整数,当您添加0.01时,它将永远不会递增。将x设为Double。实际上,通过允许编译器找出正确的类型,您可以省去更多的麻烦

For x = 0 To totalTime Step 0.01 ' it is now Double

并在代码文件的顶部添加Option Strict On仍然可以为您找到问题

For x As Integer = 0 To totalTime Step 0.01
  

Option Strict On不允许从'Double'到'Integer'的隐式转换

另一个答案和注释建议您应该调试代码。当然,调试会在这里为您提供帮助。如果我是你,我会让它运行,在For循环中放置一个断点,然后检查发生了什么。很明显,循环变量不会增加。

根据另一个答案,您可以将Console.WriteLine添加到循环中。这条线在循环中会很好地工作

Console.WriteLine($"Inside For loop, x:{x}, xPos:{xPos}, yPos:{yPos}")

那会说

  

内部For循环,x:0,xPos:0,yPos:10
  内部For循环,x:0,xPos:0,yPos:10
  内部For循环,x:0,xPos:0,yPos:10
  内部For循环,x:0,xPos:0,yPos:10
  在For循环内,x:0,xPos:0,yPos:10

您希望值在哪里更改。他们做过一次Double

  

内部For循环,x:0,xPos:0,yPos:10
  内部For循环,x:0.01,xPos:0.0707106781186548,yPos:11.6202267316012
  内部For循环,x:0.02,xPos:0.14142135623731,yPos:12.3327679741871
  内部For循环,x:0.03,xPos:0.212132034355964,yPos:12.8959725661313
  内部For循环,x:0.04,xPos:0.282842712474619,yPos:13.3818748194396396

我仍然不认为这是完整的。

没有理由在UI上运行整个循环。因此,将您的处理和UI分开。有很多方法可以实现这一目标。一种是使用Async/Await,我认为这是最简单的方法。请了解,在关闭UI时,您需要调用回呼到UI的调用才能在其中进行任何更新。

您创建的最大性能命中值是,自时间上每增加0.01点,便为图表添加注释。这真的有必要吗?在不添加注释的情况下,绘制速度非常快。有了注释,它很快就会慢下来。

一旦y达到零,是否需要继续处理?我添加了一些逻辑,可以在发生循环后退出循环。

请注意,等待会从用户界面发送代码,因此您的用户界面在运行时将是交互式的。这是一些证明这一点的代码。请注意,注释每0.1秒而不是0.01秒添加一次。他们被有效地淘汰。您可以随意使用它,以使其按需使用。

Private gConstant As Double = 9.8
Private totalTime As Double
Private velocity As Double
Private angle As Double
Private elevation As Double
Private heightOfProjectile As Double
Private flightRange As Double

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    totalTime = 100
    velocity = 100
    angle = Math.PI / 4
    elevation = 100
    heightOfProjectile = 10
    flightRange = 10
    Chart1.ChartAreas(0).AxisX.Minimum = 0
    Chart1.Series("Projection").ChartType = SeriesChartType.FastLine
    Await Task.Factory.StartNew(AddressOf getPoints)
End Sub

Private Sub getPoints()
    For x As Double = 0 To totalTime Step 0.01
        Dim xPos As Double = findXLocation(velocity, angle, x)
        Dim yPos As Double = findYLocation(velocity, angle, x, elevation, totalTime, heightOfProjectile, flightRange)
        Dim l = x
        Chart1.Invoke(
            Sub()
                Chart1.Series("Projection").Points.AddXY(xPos, yPos)
                If CInt(100 * l) Mod 10 = 0 Then Chart1.Annotations.Add(New CalloutAnnotation())
            End Sub)
        Console.WriteLine($"Inside For loop, x:{x}, xPos:{xPos}, yPos:{yPos}")
        If yPos = 0 Then Exit For
    Next
End Sub

Public Function findYLocation(ByVal velocity As Double, ByVal angle As Double, ByVal time As Double, ByVal elevation As Double, ByVal totalTime As Double, ByVal heightOfProjectile As Double, ByVal flightRange As Double) As Double
    Return Math.Max(0, -0.5 * gConstant * sq(time) + findVerticalVelocity(velocity, angle) * time + elevation)
End Function

Private Function sq(value As Double) As Double
    Return value ^ 2
End Function

Public Function findXLocation(ByVal velocity As Double, ByVal angle As Double, ByVal time As Double) As Double
    Return Math.Max(0, findHorizontalVelocity(velocity, angle) * time)
End Function

Private Function findVerticalVelocity(velocity As Double, angle As Double) As Double
    Return Math.Sin(angle) * velocity
End Function

Private Function findHorizontalVelocity(velocity As Double, angle As Double) As Double
    Return Math.Cos(angle) * velocity
End Function

enter image description here