C#:在winform上使用定时器来改变图表,定时器需要单独的方法,图表数据不能从单独的方法中编辑

Posted

技术标签:

【中文标题】C#:在winform上使用定时器来改变图表,定时器需要单独的方法,图表数据不能从单独的方法中编辑【英文标题】:C#: Using a timer on a winform to alter a chart, timer needs a separate method, chart data can't be edited from the separate method 【发布时间】:2019-06-30 18:50:22 【问题描述】:

enter image description here我正在做一个小项目,以帮助我对图表和winforms 更加陈旧。我决定制作一个模拟弹丸运动的 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) 用户输入恒定加速度作为矢量,与速度相同。 并且用户输入他们想要为其建模的时间量。 用户然后单击模型以绘制图形。 用户可以单击清除以清空图形。

附:我有清除按钮,但理想情况下,我希望能够在同一个图表上模拟多个射弹。我知道更简单的方法可能是添加一个系列,或者我想被允许建模的数量,但我想问是否有办法让同一系列中的下一个点成为一个新位置,而实际上没有一条线从图表末尾到新位置?

【问题讨论】:

【参考方案1】:

您可以在不显式使用计时器的情况下获得所需的结果。

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

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。

【讨论】:

你好。非常感谢你的答复。我想我有点明白你在说什么。为了更好地理解它,我想我先复制它并将其粘贴到我的代码中,然后看看它做了什么。问题是,StartUpdatingChart() 不是我拥有的方法,我是不是打算做一个?此外,如果我错了,请纠正我,但 FormLoad 方法从表单加载开始。我不希望它从表单加载的那一刻起就尝试绘制它,因为我需要几个变量和一个按钮来触发图形。 @NurLuskiLevi,如果您复制了代码,那么 StartUpdatingChart 应该在该副本中(它在答案中);)。您可以从任何其他方法开始更新图表,FormLoad 就是一个例子。

以上是关于C#:在winform上使用定时器来改变图表,定时器需要单独的方法,图表数据不能从单独的方法中编辑的主要内容,如果未能解决你的问题,请参考以下文章

.net C# winform程序定时运行代码

winform c# 如写一个定时开始,结束的时间代码

winform 添加鼠标移动监听

C# winForm 定时拷贝覆盖文件小工具

C#中Timer定时器的使用示例

C#定时器怎么写?