So far I have been successful in plotting a chart with the following code, but I want it to draw and connect the data points over time, not just all at once. For example, I might want it to take a total of 60 seconds to plot all of the points. How can I do this?
chart1.Series["test1"].ChartType = SeriesChartType.FastLine;
chart1.Series["test1"].Color = Color.Red;
chart1.Series["test2"].ChartType = SeriesChartType.FastLine;
chart1.Series["test2"].Color = Color.Blue;
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));
}
You can create a DispatcherTimer and set its Interval to the amount of time you want to wait between points plotted. Give it a Tick event handler that adds the next point to the chart, and disable the timer when you're done.
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(0.1d),
};
var pointsRemaining = 50;
var r = new Random();
timer.Tick += (sender, args) =>
{
if (--pointsRemaining == 0)
timer.Stop();
chart1.Series["test1"].Points.AddXY(r.Next(0,10), r.Next(0,10));
chart1.Series["test2"].Points.AddXY(r.Next(0,10), r.Next(0,10));
};
timer.Start();
Related
I'm trying to develop some sort of "animation" for a control in winforms that will run in a new thread than the main one.
So the code I used for the animation is the one I leave you below (a label control that scrolls up pixel by pixel every few seconds until it reaches 0 pixels):
private void LabelAnimation(int amount)
{
this.Invoke((MethodInvoker)delegate
{
int currentX = Label.Location.X;
Label.Text = amount.ToString();
for (int h = 1; h < 7; h++)
{
int subtractHeight = h;
int currentY = Label.Location.Y;
Label.Location = new Point(currentX, (currentY - subtractHeight));
Thread.Sleep(200);
}
});
}
And the method in which the new thread is created:
private void ExecuteAnimation()
{
Thread t = new Thread(() => LabelAnimation(100));
t.Start();
}
The problem is that in itself it works but on a graphic level it sucks, I mean, instead of moving the entire control, the text string remained in the same position while the rectangle of the label moved in the indicated direction, covering its own string.
Use System.Timers.Timer.
It`s recommended to use a timer instead of sleeping the thread.
Here is one way to achieve this:
private System.Timers.Timer timer;
private int amount = 100;
private void ExecuteAnimation()
{
new Thread(() =>
{
// Set DoubleBuffered to true for smoother animation
this.DoubleBuffered = true;
if (timer == null)
{
timer = new System.Timers.Timer();
timer.Interval = 100;
timer.Elapsed += timer_tick;
}
timer.Start();
}).Start();
}
private void timer_tick(object sender, EventArgs e)
{
this.Invoke(new Action(() =>
{
int currentX = label1.Location.X;
label1.Text = amount.ToString();
if (label1.Location.Y > 0)
{
label1.Location = new Point(currentX, label1.Location.Y - 1);
}
}));
}
OUTPUT:
In addition to Jonathans fine answer, you might also be interested in this "Component Animator":
https://www.codeproject.com/Articles/548769/Animator-for-WinForms
If it could be useful to someone else, I finally solved the problem by mixing the #Jonathan Applebaum code and mine, like so:
private void LabelAnimation(int amount, int moveUp)
{
int currentX = 0;
this.Invoke(new Action(() =>
{
currentX = Label.Location.X;
Label.Text = amount.ToString();
}));
for (int h = 1; h < moveUp; h++)
{
this.Invoke(new Action(() =>
{
int currentY = Label.Location.Y;
Label.Location = new Point(currentX, (currentY - h));
}));
Thread.Sleep(150);
}
}
The thread execution always remains the same:
private void ExecuteAnimation()
{
Thread t = new Thread(() => LabelAnimation(100, 7));
t.Start();
}
In this way I make only the gets or sets related to the Label control run on the main thread while everything else, including the Thread.Sleep(150), in the secondary thread so as to avoid the Form getting stuck. In this way everything runs smoothly for me.
My requirement is in my line graph( which is developed with c# MS Chart), I
always need to display 10 points(samples) at a time. The xaxis has interval value 1.
Initially the Xaxis tick values are (1,2,3,4,5,6,7,8,9,10), After 1 second of time interval, I
have to plot 10 points(samples) starts from 2nd point(i.e. I have to skip 1st
point).Now I need to update the xaxis tick values also , it should be starts from
2,now the xaxis tick values should be like 2,3,4,5,6,7,8,9,10,11). Likewise
After every second the starting value of x axis
tick needs to be increased by 1.
How to update Xaxis tick value in the chart dynamically ?
I am using below code
private void Form1_Load(object sender, EventArgs e)
{
loadCsvFile("C:\\mydata.csv");
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.timer1 = new System.Windows.Forms.Timer(this.components);
chart = new System.Windows.Forms.DataVisualization.Charting.Chart();
chart.Location = new System.Drawing.Point(1, 1);
chart.Size = new System.Drawing.Size(700, 700);
// Add a chartarea called "draw", add axes to it and color the area black
chart.ChartAreas.Add("draw");
numofSamples = 10;
chart.ChartAreas["draw"].AxisX.Minimum = 1;
chart.ChartAreas["draw"].AxisX.Maximum = 10;
chart.ChartAreas["draw"].AxisX.Interval = 1;
chart.ChartAreas["draw"].AxisX.Title = "X Axis";
chart.ChartAreas["draw"].AxisX.MajorGrid.LineColor = System.Drawing.Color.Black;
chart.ChartAreas["draw"].AxisX.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["draw"].AxisY.Minimum = 0;
chart.ChartAreas["draw"].AxisY.Maximum = 1000;
chart.ChartAreas["draw"].AxisY.Interval = 250;
chart.ChartAreas["draw"].AxisY.Title = "Y Axis";
chart.ChartAreas["draw"].AxisY.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["draw"].AxisY.MajorGrid.LineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Dash;
chart.ChartAreas["draw"].BackColor = Color.White;
// Create a new function series
chart.Series.Add("Tags");
// Set the type to line
chart.Series["Tags"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
// Color the line of the graph light green and give it a thickness of 3
chart.Series["Tags"].Color = Color.LightGreen;
chart.Series["Tags"].BorderWidth = 3;
chart.Series["Tags"].MarkerStyle = MarkerStyle.Circle;
chart.Series["Tags"].MarkerSize = 10;
chart.Legends.Add("MyLegend");
chart.Legends["MyLegend"].BorderColor = Color.Tomato; // I like tomato juice!
Controls.Add(this.chart);
// hook up timer event
this.timer1.Interval = 1000;
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
timer1.Start();
}
public void loadCsvFile(string filePath)
{
var reader = new StreamReader(File.OpenRead(filePath));
while (!reader.EndOfStream)
{
List<string> listA = new List<string>();
string line = reader.ReadLine();
mList.Add(line );
}
}
int i = 0;
int n = 0;
private void timer1_Tick(object sender, EventArgs e)
{
if (n > 20)
n = 0;
int j=0;
chart.Series["Tags"].Points.Clear();
for (i=n; i < mList.Count; i++)
{
string l =mList[i];
chart.Series["Tags"].Points.AddY(l);
j++;
if (j == 10)
break;
}
n++;
chart.Update();
}
List<List<string>> mList = new List<List<string>>();
I would like to create "rolling numbers" on a windows form for about 10 seconds.
I've tried with loops but i got problems with refresh (the forms freezes and updates when the loop is done) updating a text label.
It would be nice when it looks like this https://youtu.be/Q7JmiCAAqu0 (made on console)
Sorry for bad english ^^
Drag one Label on your Form and one Timer.
Insert the following code after 'InitializeComponent();
const int maximum = 100;
int actual = 0;
timer1.Interval = 100;
timer1.Enabled = true;
timer1.Tick += (sender, args) =>
{
label1.Text = (actual++ % maximum).ToString();
};
Explanation:
Label is used to show the rolling numbers
Timer is used to perform an operation every N miliseconds (in our case every 100ms = 0.1s)
const int maximum = 100; // defines the maximum number we want to show
int actual = 0; // represents the actual number we are showing at a time
timer1.Interval = 100; // interval after which the timer1.Tick is called (in our case 100ms)
timer1.Enabled = true; // enables the timer, without it the Tick would not get called
timer1.Tick += (sender, args) =>
{
label1.Text = (actual++ % maximum).ToString(); // set the text to: actual + 1 modulo 100
};
EDIT: Information about modulo: https://en.wikipedia.org/wiki/Modulo_operation
My program creates 5 different labels with a cube form and they just drop down. When I press on them, they come invisible. I want to check if all of them are invisible, but don't know how to do so. Tried going through this site, found a solution with bool, but it just doesn't work my way. Also when my labels appear,you can see only 4 of them.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Label [] kubeliai = new Label [5];
int poz = 100;
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < kubeliai.Length; i++)
{
kubeliai[i] = new Label();
Controls.Add(kubeliai[i]);
Random pos = new Random();
kubeliai[i].Top = 50;
kubeliai[i].Left = poz;
poz += pos.Next(50, 200);
kubeliai[i].BackColor = Color.Red;
kubeliai[i].Height = 20;
kubeliai[i].Width = 20;
kubeliai[i].Click += new EventHandler(kubelio_clickas);
}
Timer kritimo_laikrodis = new Timer();
kritimo_laikrodis.Interval = 10;
kritimo_laikrodis.Tick += new EventHandler(laikrodis);
kritimo_laikrodis.Enabled = true;
}
void kubelio_clickas (object sender, EventArgs e)
{
((Label)sender).Visible = false;
}
void laikrodis (object sender, EventArgs e)
{
for (int i = 0; i < kubeliai.Length; i++)
{
kubeliai[i].Top += 1;
if (kubeliai.All.Visible == false) // this is an error
{
kubeliai[i].Visible = true;
kubeliai[i].Top = 50;
Random pos = new Random();
poz += pos.Next(50, 200);
}
}
}
Using Linq you can check if all are invisible in this way
var areAllInvisible = kubeliai.All(l => l.Visible == false);
if (areAllInvisible)
{
// do something
}
when my labels appear you can see only 4 of them.
That's because the way you are picking random numbers is picking the same numbers each time and you are therefore placing your labels on top of each other. Read the first paragraph of the Random() documentation:
Different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a single Random object to generate all random numbers.
Use new Random() once in your class definition like this:
Label [] kubeliai = new Label [5];
Random pos = new Random();
And remove it everywhere else in your program.
I use a .NET Winform version teechart 4.1.2014.8126 evalution version.
When I zoom in / out chart using downsampling function, Something is wrong.
Look at the below picture.
This is a chart using downsampling function. We can see about 50 ~60 visible mark point.
This is a zoom in chart 1 time. We can see about 16 ~ 20 visible mark point.
Why visible count is decrease when I zoom in? I want more detail view, when I zoom in chart.
private void InitializeChart()
{
this.cursorTool1 = new Steema.TeeChart.Tools.CursorTool();//
this.tChart1.Tools.Add(this.cursorTool1);//
this.cursorTool1.FollowMouse = true;//
this.cursorTool1.Style = Steema.TeeChart.Tools.CursorToolStyles.Vertical;//
this.cursorTool1.Change += new Steema.TeeChart.Tools.CursorChangeEventHandler(this.cursorTool1_Change);//
CreateArrays();
tChart1.Aspect.View3D = false;
tChart1.Zoom.Direction = ZoomDirections.Both;//.Horizontal;//
tChart1.Series.Add(points = new Steema.TeeChart.Styles.Points());
tChart1.Series.Add(fastLine = new Steema.TeeChart.Styles.FastLine());
downSampling = new Steema.TeeChart.Functions.DownSampling(tChart1.Chart);
points.Add(xValues, yValues);
points.Active = false;
int pixelCount = 60;
downSampling.DisplayedPointCount = pixelCount;
downSampling.Method = Steema.TeeChart.Functions.DownSamplingMethod.MinMaxFirstLast;// Null;
fastLine.TreatNulls = Steema.TeeChart.Styles.TreatNullsStyle.DoNotPaint;
fastLine.DataSource = points;
fastLine.Function = downSampling;
this.tChart1.Axes.Custom.Add(new Steema.TeeChart.Axis(this.tChart1.Chart));//
this.tChart1[1].CustomVertAxis = this.tChart1.Axes.Custom[0];//
this.tChart1[0].CustomVertAxis = this.tChart1.Axes.Custom[0];//
this.fastLine.Marks.Visible = true;//
}
private void CreateArrays()
{
int length = 100000;
xValues = new Nullable<double>[length];
yValues = new Nullable<double>[length];
Random rnd = new Random();
for (int i = 0; i < length; i++)
{
xValues[i] = i;
yValues[i] = i;
}
}
private void tChart1_Zoomed(object sender, EventArgs e)
{
tChart1[1].CheckDataSource(); //series 1 is the function series
}
This is not a defect, but expected behaviour. If we add the following code to your example (with the relevant event declaration):
void tChart1_AfterDraw(object sender, Graphics3D g)
{
string s = "Count: " + tChart1[1].Count.ToString() + Utils.NewLine
+ "Displayed Count: " + (tChart1[1].LastVisibleIndex - tChart1[1].FirstVisibleIndex).ToString();
tChart1.Header.Text = s;
}
We can see that "Count" is what you have defined in your variable "pixelCount" and "Displayed Count" decreases as the bottom axis maximum and minimum move closer together.
I think you are expecting the "Displayed Count" to increase as the bottom axis maximum and minimum move closer together, but this is not going to happen as long as the series "Count" remains the same. To increase the series "Count" on zooming you will have to increase the value of "pixelCount" and recalculate.