C#:在winform上使用计时器来更改图表,计时器需要使用单独的方法,无法使用单独的方法来编辑图表数据

时间:2019-02-06 18:13:21

标签: c# multithreading winforms timer

enter image description here我正在做一个小项目,以帮助我更加熟悉图表和Winform。我决定制作一个模拟弹丸运动的xy图(x是x位移,y是y位移,时间上的参数变量t)。我能够使其正常运行,但一个朋友向我提出挑战,要求我尝试使其实时动画化。我发现了一些有关计时器和经过时间的基本信息,但后来发现自己陷入了麻烦。在每个计时器上执行某项操作需要一定的计时器时间才能调用一个事件(这显然是一个线程?我对线程完全不熟悉),并且无法从一个窗口编辑用于Winforms图表线的系列。根据Visual Studio的错误,线程(除了在上面创建的那个线程)(在这种情况下,我假设出于所有目的和目的只是一种方法?)。

我是一个相当精明的新程序员,我对现存的C#很了解,但是到目前为止,我更愿意使用它而不将其绑定到对象(我被告知我像C一样使用c#?)。因此,尽管这可能比复杂的事情要复杂得多,但这只是我在进行了一些研究和探索后才想到的。我在这里还没有尝试太多,所以我不知道该怎么做。我很困

public InputAndChart()
    {
        InitializeComponent();
    }

    private System.Timers.Timer aTimer;
    private System.Timers.Timer totalTimer;
    public int i;

    private void Model_Click(object sender, EventArgs e)
    {
        #region x suvat variables
        double initialsx = Convert.ToDouble(Initialsx.Text);
        double sx;
        double ux = Convert.ToDouble(Initialux.Text);
        double vx = 5;
        double ax = Convert.ToDouble(Initialax.Text);
        #endregion
        #region y suvat variables
        double initialsy = Convert.ToDouble(Initialsy.Text);
        double sy;
        double uy = Convert.ToDouble(Initialuy.Text);
        double vy = -93;
        double ay = Convert.ToDouble(Initialay.Text);
        #endregion
        #region Setting other Variables
        double t = 10;
        double totalTime = Convert.ToDouble(TotalTime.Text);
        aTimer = new System.Timers.Timer();
        aTimer.Interval = 2000;
        aTimer.AutoReset = true;
        totalTimer = new System.Timers.Timer();
        totalTimer.Interval = totalTime * 1000;
        totalTimer.AutoReset = false;
        #endregion

        aTimer.Enabled = true;

        aTimer.Elapsed += ThreadProcSafe;
        totalTimer.Elapsed += DisableaTimer;

        #region Previous for loop
        /*
        for (int i = 0; i < totalTime * 10; i++)
        {
            t = 0.1 * i;
            sx = initialsx + ux * t + 0.5 * ax * Math.Pow(t, 2);
            sy = initialsy + uy * t + 0.5 * ay * Math.Pow(t, 2);
            chart1.Series["Curve 1"].Points.AddXY(sx, sy);
        }
        */
        #endregion

        #region Random copied test points
        /*
        Random rdn = new Random();
        for (int i = 0; i < 50; i++)
        {
            chart1.Series["test1"].Points.AddXY
                            (rdn.Next(0, 10), rdn.Next(0, 10));
            chart1.Series["test2"].Points.AddXY
                            (rdn.Next(0, 10), rdn.Next(0, 10));
        }
        */
        #endregion

        chart1.Series["Curve 1"].ChartType =
                            SeriesChartType.FastLine;
        chart1.Series["Curve 1"].Color = Color.Red;

    }

    private void DisableaTimer(Object source, System.Timers.ElapsedEventArgs e)
    {
        aTimer.Enabled = false;
    }

    private void ThreadProcSafe(Object source, System.Timers.ElapsedEventArgs e)
    {
        #region x suvat variables
        double initialsx = Convert.ToDouble(Initialsx.Text);
        double sx;
        double ux = Convert.ToDouble(Initialux.Text);
        double vx = 5;
        double ax = Convert.ToDouble(Initialax.Text);
        #endregion
        #region y suvat variables
        double initialsy = Convert.ToDouble(Initialsy.Text);
        double sy;
        double uy = Convert.ToDouble(Initialuy.Text);
        double vy = -93;
        double ay = Convert.ToDouble(Initialay.Text);
        #endregion
        double t;
        t = 0.1 * i;
        sx = initialsx + ux * t + 0.5 * ax * Math.Pow(t, 2);
        sy = initialsy + uy * t + 0.5 * ay * Math.Pow(t, 2);
        chart1.Series["Curve 1"].Points.AddXY(sx, sy);
        i += 1;
    }

好吧,我希望获得的理想输出是,在这种情况下绘制的图表将是每秒绘制一个点。一旦完成该工作,我便会调整时间,以使其感觉像是更平滑的曲线。天哪,我很可能会使计时器与总时间成正比。

我添加了这张图片,以帮助您了解我想要的东西。快速说明: 用户将初始位置输入为xtextbox ytextbox 用户输入初始速度作为矢量(又称i和j,但不包含i和j) 用户输入恒定加速度作为矢量,与速度相同。 然后,用户输入他们要对此建模的时间。 然后,用户单击模型以绘制图形。 用户可以单击清除以清空图形。

P.S。我具有清除按钮,但理想情况下,我希望能够在同一张图中对多个弹丸进行建模。我知道更简单的方法可能是添加一个序列,或者添加一个我想建模的序列,但是我想问一问是否有一种方法可以使同一序列中的下一个点变成新的位置,而实际上没有一行从图表末尾到新位置?

1 个答案:

答案 0 :(得分:0)

您无需显式使用计时器即可获得所需的结果。

采用异步方法,该方法在每个给定间隔后将更新图表。
我们还需要两个辅助变量

private int _intervalMilliseconds;
private bool _runUpdating;

private void UpdateChart()
{
    // x suvat variables
    double initialsx = Convert.ToDouble(Initialsx.Text);
    double ux = Convert.ToDouble(Initialux.Text);
    double vx = 5;
    double ax = Convert.ToDouble(Initialax.Text);

    // y suvat variables
    double initialsy = Convert.ToDouble(Initialsy.Text);
    double uy = Convert.ToDouble(Initialuy.Text);
    double vy = -93;
    double ay = Convert.ToDouble(Initialay.Text);

    double t = 0.1 * i;
    double sx = initialsx + ux * t + 0.5 * ax * Math.Pow(t, 2);
    double sy = initialsy + uy * t + 0.5 * ay * Math.Pow(t, 2);

    chart1.Series["Curve 1"].Points.AddXY(sx, sy);
    i += 1;
}

private async Task StartUpdatingChart()
{
    while (_runUpdating)
    {
        UpdateChart();
        await Task.Delay(_intervalMilliseconds);
    }
}

然后例如在FormLoad事件处理程序中开始更新图表

// We need preserve updating task to close it properly
private Task _updatingTask;

private async void FormLoad(object sender, EventArgs e)
{
     _runUpdating = true;
     _intervalMilliseconds = 1000;
     _updatingTask = StartUpdatingChart();
}

private async void FormClosed(object sender, EventArgs e)
{
     _runUpdating = false;
     // await for task to be completed
     await _updatingTask;
}

使用异步方法,所有操作将在同一线程上执行。 Task.Delay除外,它将在后台使用Timer。