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上使用定时器来改变图表,定时器需要单独的方法,图表数据不能从单独的方法中编辑的主要内容,如果未能解决你的问题,请参考以下文章